Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eddf2b0339 |
@@ -1,154 +1,61 @@
|
||||
|
||||
Latest Version:
|
||||
Robomongo 1.0 (21 Apr, 2017)
|
||||
http://blog.robomongo.org/robomongo-1-0
|
||||
Latest Release:
|
||||
Robomongo 0.9.0 RC10 (Aug 8, 2016)
|
||||
http://blog.robomongo.org/robomongo-rc10/
|
||||
|
||||
Robomongo 1.x:
|
||||
Major Features:
|
||||
- Replica set support.
|
||||
- Update Notifications Bar
|
||||
- Welcome Tab
|
||||
- New operation logging for almost all operations.
|
||||
|
||||
Major Fixes/Improvements:
|
||||
- Improved error handling (no double error windows) for almost all operations.
|
||||
- Timestamp value is represented incorrectly (https://github.com/Studio3T/robomongo/issues/1159)
|
||||
- Local Timezone shows wrong date (https://github.com/Studio3T/robomongo/issues/501)
|
||||
|
||||
* What's new in patch 1.0.3 (7 June, 2017)
|
||||
- Attempt to prevent MAC OS Sierra crash related to updates notification bar
|
||||
|
||||
* What's new in 1.0 (21 Apr, 2017)
|
||||
New Features:
|
||||
- Update Notifications Bar
|
||||
- Welcome Tab
|
||||
- Welcome Wizard
|
||||
|
||||
Improvements:
|
||||
- Replica set name configurable on UI
|
||||
- Configuration file system location change
|
||||
- "About Robomongo" dialog changes
|
||||
|
||||
Fixes:
|
||||
- Fix to avoid the same set name problem (https://github.com/Studio3T/robomongo/issues/1302)
|
||||
- Timestamp value is represented incorrectly (https://github.com/Studio3T/robomongo/issues/1159)
|
||||
- Local Timezone shows wrong date (https://github.com/Studio3T/robomongo/issues/501)
|
||||
- Time zone shown as "000:00" when UTC +00:00 is used as local timezone(https://github.com/Studio3T/robomongo/issues/1309)
|
||||
|
||||
* What's new in 1.0-RC1 (1 Feb, 2017)
|
||||
New Features:
|
||||
- Replica set support.
|
||||
- New 'Attributes' column in connections list window showing connection properties such as 'Replica Set', 'SSL' and 'SSH'.
|
||||
- New operation logging for almost all operations.
|
||||
|
||||
Improvements:
|
||||
- Improved error handling (no double error windows) for all fail and success conditions for the following operations:
|
||||
. Create, Drop Database
|
||||
. Create, Edit User
|
||||
. Create, Drop, Duplicate, Rename Collection
|
||||
. Insert Document
|
||||
. Remove document, Delete document, Remove all documents (triggered both from explorer and from result widget)
|
||||
. Refresh Users
|
||||
. Refresh Functions
|
||||
. Refresh Collections
|
||||
. Connection establish & refresh server fail and success cases.
|
||||
- Windows size is saved and restored for Edit, View and Insert Document dialogs.
|
||||
- Connections are automatically imported from the latest Robomongo version.
|
||||
- Better error reporting/handling and logging have been added for the operations below:
|
||||
. Create, Drop Function
|
||||
. Drop User
|
||||
- More informative and adjusted log level prefix strings haven added for log window. (Error, Warn, Info etc..).
|
||||
- After a new connection is created, now the focus goes to the newly created connection (end of list) instead of the
|
||||
beginning of connections list. And when Robomongo is opened, the focus goes to the end of the connection list instead
|
||||
of beginning.
|
||||
- Error messages added and error handling for 'remove document', 'remove all documents' operations triggered explorer
|
||||
and single or multi 'delete document' from results window have been re-implemented and improved.
|
||||
- Relevant errors are shown for the following cases now:
|
||||
. Drop attempt of non-existing collection.
|
||||
. Duplicating a collection with a collection name which already exists finishes silently.
|
||||
|
||||
Fixes:
|
||||
- Fix for the problem where the connections list comes empty if the Robomongo config file or it's directory do not exist.
|
||||
- Fix for the problem where 'in-progress bar' widget was not centered on main window for "Update Documents/Remove Documents"
|
||||
operations. https://github.com/paralect/robomongo/issues/1256
|
||||
- Fix for two problems where the operations 'insert or update documents' in one tab was causing auto reloading of other
|
||||
unrelated tabs and also multiple error windows to popup. https://github.com/paralect/robomongo/issues/1236
|
||||
- Fix for the problem where the operations 'remove document', 'remove all documents' triggered explorer and single or
|
||||
multi 'delete document' from results window were causing auto reloading of other unrelated tabs.
|
||||
|
||||
|
||||
Robomongo 0.9:
|
||||
Major Features:
|
||||
- Support for MongoDB 3.x and WiredTiger engine. Robomongo now embeds MongoDB 3.2 shell.
|
||||
(Ability to use the latest shell functionality)
|
||||
- SSH tunnel support for connections
|
||||
- SSL support
|
||||
- MongoDB Atlas (Cloud MongoDB) support
|
||||
- Both MONGODB-CR and SCRAM-SHA-1 authentication mechanisms are supported.
|
||||
- Allow direct connections to Replica Set members and support IPv6 protocol.
|
||||
- Loading of huge list of collections is now faster.
|
||||
- Create Collection dialog is now expandable to support all advanced options.
|
||||
(Supporting all major mongoDB versions 3.2, 3.0, 2.6 and all storage engine types (WiredTiger
|
||||
and MMAPV1) is added.)
|
||||
- Windows High DPI support.
|
||||
- Full size editor with dockable output window.
|
||||
|
||||
Fixed:
|
||||
- Incorrect representation of floating-point numbers (fixed since RC3). This bug was a reason of a big number of issues:
|
||||
#910, #748, #697, #699, #760, #815, #870, #892,
|
||||
#894, #905, #945, #974, #978, #990, #831, #842
|
||||
- SSH connection failure to servers on Ubuntu and OS X with the following error:
|
||||
"Resource temporarily unavailable. Error when starting up SSH session: -8" (#1090)
|
||||
|
||||
|
||||
|
||||
What's new in 0.9.0 Final (30 Sep, 2016)
|
||||
http://blog.robomongo.org/robomongo-0-9-0-final/
|
||||
|
||||
New Features:
|
||||
- Full size editor with dockable output window.
|
||||
- New JSON object context menu items: "Copy Name" and "Copy Path" are added.
|
||||
- New database context menu items: "Current Operations" and "Kill Operation" are added.
|
||||
- Minimize to Tray Icon for Windows.
|
||||
|
||||
Other Changes
|
||||
- Cloud platforms Compose, mLab and Amazon EC2 were tested and added as supported platforms.
|
||||
- Maximize/Restore result button behavior and icon have been improved.
|
||||
- For better code quality and code reviews, Robomongo Code Quality and Robomongo Code Review pages have been created.
|
||||
https://github.com/paralect/robomongo/wiki/Robomongo-Code-Review
|
||||
https://github.com/paralect/robomongo/wiki/Robomongo-Code-Quality
|
||||
|
||||
Highlights from Robomongo 0.9.0 RCs:
|
||||
Major Features:
|
||||
- Support for MongoDB 3.x and WiredTiger engine. Robomongo now embeds MongoDB 3.2 shell.
|
||||
(Ability to use the latest shell functionality)
|
||||
- SSH tunnel support for connections added.
|
||||
- Support for SSL connections added.
|
||||
- MongoDB Atlas (Cloud MongoDB) support added.
|
||||
- Both MONGODB-CR and SCRAM-SHA-1 authentication mechanisms are supported.
|
||||
- Allow direct connections to Replica Set members and support IPv6 protocol.
|
||||
- Loading of huge list of collections is now faster.
|
||||
- Create Collection dialog is now expandable to support all advanced options.
|
||||
(Supporting all major mongoDB versions 3.2, 3.0, 2.6 and all storage engine types (WiredTiger
|
||||
and MMAPV1) is added.)
|
||||
- Windows High DPI support.
|
||||
|
||||
Fixed:
|
||||
- Incorrect representation of floating-point numbers (fixed since RC3). This bug was a reason of a big number of issues:
|
||||
#910, #748, #697, #699, #760, #815, #870, #892,
|
||||
#894, #905, #945, #974, #978, #990, #831, #842
|
||||
- SSH connection failure to servers on Ubuntu and OS X with the following error:
|
||||
"Resource temporarily unavailable. Error when starting up SSH session: -8" (#1090)
|
||||
|
||||
What's new in RC10 (Aug 8, 2016)
|
||||
http://blog.robomongo.org/robomongo-rc10/
|
||||
|
||||
New Features:
|
||||
- SSL connections with advanced options are now supported.
|
||||
- MongoDB Atlas (Cloud MongoDB) is supported.
|
||||
- Cross Platform High DPI enhancements.
|
||||
|
||||
Enhancements:
|
||||
- For better security, OpenSSL has been upgraded to OpenSSL 1.0.1p.
|
||||
- Qt has been updated from Qt 5.5 to latest Qt 5.7. With this update there are many
|
||||
enhancements including cross platform High DPI support.
|
||||
New Features:
|
||||
- SSL connections with advanced options are now supported.
|
||||
- MongoDB Atlas (Cloud MongoDB) is supported.
|
||||
- Cross Platform High DPI enhancements.
|
||||
|
||||
Enhancements:
|
||||
- For better security, OpenSSL has been upgraded to OpenSSL 1.0.1p.
|
||||
- Qt has been updated from Qt 5.5 to latest Qt 5.7. With this update there are many
|
||||
enhancements including cross platform High DPI support.
|
||||
|
||||
What's new in RC9 (May 30, 2016)
|
||||
http://blog.robomongo.org/robomongo-rc9/
|
||||
|
||||
New Features:
|
||||
- Create Collection dialog with advanced options.
|
||||
- New feature has been added to save/restore window sizes. (#1102)
|
||||
- Connection settings from previous versions of Robomongo are
|
||||
now automatically imported starting from Robomongo 0.9.0 RC9. (#1086)
|
||||
- Support for querying documents by UUIDs is added, both in legacy and new encoding. (#432)
|
||||
|
||||
Fixed:
|
||||
- SSH connection failure to servers on Ubuntu and OS X with the following error:
|
||||
"Resource temporarily unavailable. Error when starting up SSH session: -8" (#1090)
|
||||
- Correct handling of create/drop of databases and collections. (#1083)
|
||||
|
||||
New Features:
|
||||
- Create Collection dialog with advanced options.
|
||||
- New feature has been added to save/restore window sizes. (#1102)
|
||||
- Connection settings from previous versions of Robomongo are
|
||||
now automatically imported starting from Robomongo 0.9.0 RC9. (#1086)
|
||||
- Support for querying documents by UUIDs is added, both in legacy and new encoding. (#432)
|
||||
|
||||
Fixed:
|
||||
- SSH connection failure to servers on Ubuntu and OS X with the following error:
|
||||
"Resource temporarily unavailable. Error when starting up SSH session: -8" (#1090)
|
||||
- Correct handling of create/drop of databases and collections. (#1083)
|
||||
|
||||
What's new in RC8 (April 14, 2016)
|
||||
http://blog.robomongo.org/robomongo-rc8/
|
||||
|
||||
|
||||
What's new in RC7 (March 4, 2016)
|
||||
http://blog.robomongo.org/robomongo-rc7
|
||||
|
||||
@@ -223,7 +130,7 @@ Robomongo 0.9:
|
||||
* [Andres Kievsky]
|
||||
- Added new app icon in a variety of png and iDraw formats (#693)
|
||||
* [Michael Steinacher]
|
||||
- Retina text display support (#724)
|
||||
- Retina text display support (#724)
|
||||
|
||||
0.8.4 / November 27, 2013
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ project(Robomongo)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
|
||||
|
||||
# Project version
|
||||
set(PROJECT_VERSION_MAJOR "1")
|
||||
set(PROJECT_VERSION_MINOR "0")
|
||||
set(PROJECT_VERSION_PATCH "3")
|
||||
set(PROJECT_VERSION_BUILD "")
|
||||
set(PROJECT_VERSION_MAJOR "0")
|
||||
set(PROJECT_VERSION_MINOR "9")
|
||||
set(PROJECT_VERSION_PATCH "0")
|
||||
set(PROJECT_VERSION_BUILD "-RC10")
|
||||
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${PROJECT_VERSION_BUILD}")
|
||||
|
||||
# Modules
|
||||
@@ -27,8 +27,6 @@ find_package(Qt5Core REQUIRED)
|
||||
find_package(Qt5Gui REQUIRED)
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
find_package(Qt5PrintSupport REQUIRED)
|
||||
find_package(Qt5Network REQUIRED)
|
||||
find_package(Qt5Xml REQUIRED)
|
||||
find_package(MongoDB REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Robomongo, shell-centric cross-platform MongoDB management tool.
|
||||
|
||||
Copyright 2014-2017 3T Software Labs Ltd.
|
||||
Copyright 2013, Paralect.
|
||||
|
||||
The Robomongo is released under the terms of the GNU General Public
|
||||
License, version 3.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
About Robomongo [](https://gitter.im/paralect/robomongo?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
About Robomongo
|
||||
===============
|
||||
|
||||
[Robomongo](http://www.robomongo.org) is a shell-centric cross-platform MongoDB management tool. Unlike most other MongoDB admin UI tools, Robomongo embeds the actual `mongo` shell in a tabbed interface with access to a shell command line as well as GUI interaction.
|
||||
@@ -7,34 +7,31 @@ Starting from version 0.9, Robomongo is compatibile with MongoDB 3.x (including
|
||||
|
||||
Robomongo 0.8.x embeds the **MongoDB 2.4.0** shell.
|
||||
|
||||
What's new in latest Robomongo 1.0?
|
||||
What's new in latest Robomongo 0.9.0 RC10?
|
||||
====================================
|
||||
Latest release of Robomongo 1.0 includes:
|
||||
- Update Notifications Bar
|
||||
- Welcome Tab
|
||||
- Welcome Wizard
|
||||
- Replica set name configurable on UI
|
||||
- Fixes to avoid same replica set name problem
|
||||
- Fixes to solve various problems regarding Data and Timestamp data types
|
||||
Latest release of Robomongo 0.9.0 RC10 includes:
|
||||
- Support for SSL
|
||||
- MongoDB Atlas Support
|
||||
- HiDPI enhancements
|
||||
|
||||
Central feature of this release is full support for TSL/SSL protocol with advanced options. This version also brings support to MongoDB Atlas cloud service and includes enhancements for HiDPI displays.
|
||||
|
||||
Blog: http://blog.robomongo.org/robomongo-1-0/
|
||||
Blog: http://blog.robomongo.org/robomongo-rc10
|
||||
Download: https://robomongo.org/download
|
||||
Watch: [Robomongo Youtube channel](https://www.youtube.com/channel/UCM_7WAseRWeeiBikExppstA)
|
||||
Follow: https://twitter.com/Robomongo
|
||||
|
||||
What's Planned for the Next Releases?
|
||||
What's Planned for the Next Release?
|
||||
====================================
|
||||
|
||||
We are currently working towards [Robomongo 2.0 milestone](https://github.com/paralect/robomongo/milestone/21).
|
||||
We are currently working towards [Robomongo 0.9.0 RC11 milestone](https://github.com/paralect/robomongo/milestone/16).
|
||||
|
||||
Currently in progress:
|
||||
- MongoDB 3.4 Support
|
||||
- Replica Sets Support
|
||||
|
||||
Plans for Future:
|
||||
- User Roles
|
||||
- Support execution of multiple simultaneous queries [#1161](https://github.com/paralect/robomongo/issues/1161)
|
||||
- Selectable mongodb engines [#1249](https://github.com/paralect/robomongo/issues/1249)
|
||||
- Enhancements for stability, running without crashes ([Stability Milestone](https://github.com/paralect/robomongo/milestone/15))
|
||||
- Enhancements for stability, running without crashes
|
||||
- More Documentation
|
||||
- Unit Tests
|
||||
- Refactoring Debug Log module
|
||||
@@ -42,19 +39,20 @@ Plans for Future:
|
||||
Supported Platforms
|
||||
===============
|
||||
|
||||
| MongoDB Versions |
|
||||
| :-------------------- |
|
||||
| 3.2 |
|
||||
| 3.0 |
|
||||
| 2.6 |
|
||||
**Supported MongoDBs:**
|
||||
|
||||
| MongoDB Cloud Platforms|
|
||||
| :------------ |
|
||||
| MongoDB Atlas |
|
||||
| Compose |
|
||||
| mLab |
|
||||
| ObjectRocket |
|
||||
| Amazon EC2 |
|
||||
| MongoDB Versions | MongoDB Cloud |
|
||||
| :-------------------- | :------------ |
|
||||
| 3.2 | MongoDB Atlas |
|
||||
| 3.0 | Compose |
|
||||
| 2.6 | mLab |
|
||||
| | ObjectRocket |
|
||||
|
||||
|
||||
|
||||
**Note**: Currently Robomongo supports connection to single server of a replica set. Support for connection to **Replica Sets** is one of the most important features of next Robomongo release plan.
|
||||
|
||||
**Supported OS Platforms:**
|
||||
|
||||
| Windows | Mac | Linux |
|
||||
|:---------------------- | :---------------| :---------------------------|
|
||||
@@ -65,13 +63,14 @@ Supported Platforms
|
||||
|
||||
\* latest stable build
|
||||
|
||||
|
||||
Download
|
||||
========
|
||||
|
||||
You can download tested install packages for OS X, Windows, and Linux from our site: [www.robomongo.org](http://www.robomongo.org).
|
||||
|
||||
The latest stable release is currently [**Robomongo 1.0**](http://blog.robomongo.org/robomongo-1-0/).
|
||||
The latest release candidate is currently **Robomongo 0.9.0 RC10**. (http://blog.robomongo.org/robomongo-rc10/).
|
||||
|
||||
The latest stable release is currently **Robomongo 0.8.5**. (http://blog.robomongo.org/whats-new-in-robomongo-0-8-5/)
|
||||
|
||||
Support
|
||||
=======
|
||||
@@ -82,7 +81,7 @@ You can:
|
||||
|
||||
- [Create a new issue in the Github issue queue](https://github.com/paralect/robomongo/issues)
|
||||
|
||||
- [Join developer discussion on Gitter](https://gitter.im/paralect/robomongo)
|
||||
- [Join developer discussion on Gitter](https://gitter.im/paralect/robomongo) [](https://gitter.im/paralect/robomongo?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
Build
|
||||
=====
|
||||
@@ -97,7 +96,6 @@ Contribute!
|
||||
### Suggest Features
|
||||
|
||||
New feature suggestions or UI improvements are always welcome.
|
||||
[Create a new feature request on github](https://github.com/paralect/robomongo/issues/new)
|
||||
|
||||
This project is powered by open source volunteers, so we have a limited amount of development resource to address all requests. We will certainly make best efforts to progress (particularly for those with strong community upvotes).
|
||||
|
||||
@@ -109,6 +107,8 @@ Code contributions are always welcome! Just try to follow our pre-commit checks
|
||||
|
||||
If you plan to contribute, please create a Github issue (or comment on the relevant existing issue) so we can help coordinate with upcoming release plans.
|
||||
|
||||
For a general workflow, see Github's guide to [Fork a Repo](https://help.github.com/articles/fork-a-repo/).
|
||||
|
||||
Pull requests (PRs) should generally be for discrete issues (i.e. one issue per PR please) and be clean to merge against the current master branch. It would also be helpful if you can confirm what testing has been done (specific O/S targets and MongoDB versions if applicable).
|
||||
|
||||
A usual naming approach for feature branches is `issue-###`. Include the issue number in your commit message / pull request description to link the PR to the original issue.
|
||||
@@ -128,7 +128,7 @@ There are a number of issues we could use help with reproducing. They are marked
|
||||
License
|
||||
=======
|
||||
|
||||
Copyright 2014-2017 [3T Software Labs Ltd](https://studio3t.com/). All rights reserved.
|
||||
Copyright (C) 2013-2016 [Paralect, Inc](http://www.paralect.com)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 3 as
|
||||
|
||||
@@ -8,8 +8,6 @@ message("| Qt5 Core: ${Qt5Core_VERSION} ${Qt5Core_DIR}")
|
||||
message("| Qt5 Gui: ${Qt5Gui_VERSION} ${Qt5Gui_DIR}")
|
||||
message("| Qt5 Widgets: ${Qt5Widgets_VERSION} ${Qt5Widgets_DIR}")
|
||||
message("| Qt5 PrintSupport: ${Qt5Widgets_VERSION} ${Qt5PrintSupport_DIR}")
|
||||
message("| Qt5 Network: ${Qt5Network_VERSION} ${Qt5Network_DIR}")
|
||||
message("| Qt5 Xml: ${Qt5Xml_VERSION} ${Qt5Xml_DIR}")
|
||||
message("| MongoDB: ${MongoDB_VERSION} ${MongoDB_BUILD_DIR}")
|
||||
message("| OpenSSL: ${OPENSSL_VERSION} ${OpenSSL_DIR}")
|
||||
message("|")
|
||||
|
||||
@@ -24,7 +24,7 @@ if(SYSTEM_LINUX)
|
||||
set(qt_conf_dir ${bin_dir})
|
||||
set(qt_conf_plugins "../lib")
|
||||
elseif(SYSTEM_MACOSX)
|
||||
set(bundle_name "Robomongo.app")
|
||||
set(bundle_name Robomongo.app)
|
||||
set(contents_path ${bundle_name}/Contents)
|
||||
|
||||
set(bin_dir ${contents_path}/MacOS)
|
||||
@@ -72,9 +72,7 @@ elseif(SYSTEM_MACOSX)
|
||||
elseif(SYSTEM_LINUX)
|
||||
install(
|
||||
FILES
|
||||
"${OpenSSL_DIR}/libssl.so"
|
||||
"${OpenSSL_DIR}/libssl.so.1.0.0"
|
||||
"${OpenSSL_DIR}/libcrypto.so"
|
||||
"${OpenSSL_DIR}/libssl.so.1.0.0"
|
||||
"${OpenSSL_DIR}/libcrypto.so.1.0.0"
|
||||
DESTINATION ${lib_dir})
|
||||
endif()
|
||||
@@ -95,7 +93,7 @@ install(
|
||||
DESTINATION ${license_dir})
|
||||
|
||||
# Install common dependencies
|
||||
install_qt_lib(Core Gui Widgets PrintSupport Network Xml)
|
||||
install_qt_lib(Core Gui Widgets PrintSupport)
|
||||
install_qt_plugins(QGifPlugin QICOPlugin)
|
||||
install_icu_libs()
|
||||
|
||||
@@ -113,7 +111,7 @@ elseif(SYSTEM_MACOSX)
|
||||
|
||||
# Install icon
|
||||
install(
|
||||
FILES "${CMAKE_SOURCE_DIR}/install/macosx/robomongo.icns"
|
||||
FILES "${CMAKE_SOURCE_DIR}/install/macosx/Robomongo.icns"
|
||||
DESTINATION "${resources_dir}")
|
||||
elseif(SYSTEM_WINDOWS)
|
||||
install_qt_plugins(
|
||||
|
||||
@@ -15,7 +15,7 @@ execute_process(
|
||||
string(TIMESTAMP timestamp "%Y-%m-%d")
|
||||
|
||||
# Package name (as it should appear in UI)
|
||||
set(CPACK_PACKAGE_NAME robomongo)
|
||||
set(CPACK_PACKAGE_NAME Robomongo)
|
||||
|
||||
# Version of the package
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
||||
@@ -34,8 +34,8 @@ set(CPACK_MONOLITHIC_INSTALL ON)
|
||||
set(CPACK_STRIP_FILES ON)
|
||||
|
||||
# Additional information
|
||||
set(CPACK_PACKAGE_VENDOR "3T Software Labs Ltd")
|
||||
set(CPACK_PACKAGE_CONTACT robomongo@3t.io)
|
||||
set(CPACK_PACKAGE_VENDOR Paralect)
|
||||
set(CPACK_PACKAGE_CONTACT robomongo@paralect.com)
|
||||
set(CPACK_PACKAGE_DESCRIPTION "Shell-centric cross-platform MongoDB management tool.")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Robomongo is a shell-centric cross-platform MongoDB management tool.")
|
||||
|
||||
@@ -62,7 +62,7 @@ elseif(SYSTEM_MACOSX)
|
||||
|
||||
elseif(SYSTEM_WINDOWS)
|
||||
set(files_dir "${CMAKE_SOURCE_DIR}/install/windows")
|
||||
set(exe_name "robomongo.exe")
|
||||
set(exe_name "Robomongo.exe")
|
||||
|
||||
set(CPACK_GENERATOR NSIS ZIP)
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/DESCRIPTION")
|
||||
|
||||
@@ -18,9 +18,9 @@ endif()
|
||||
set(PROJECT_NAME "Robomongo")
|
||||
set(PROJECT_NAME_TITLE ${PROJECT_NAME})
|
||||
set(PROJECT_DOMAIN "www.robomongo.org")
|
||||
set(PROJECT_COMPANYNAME "3T Software Labs Ltd")
|
||||
set(PROJECT_COPYRIGHT "Copyright (C) 2014-2017 ${PROJECT_COMPANYNAME} All Rights Reserved.")
|
||||
set(PROJECT_COMPANYNAME_DOMAIN "https://studio3t.com/")
|
||||
set(PROJECT_COMPANYNAME "Paralect")
|
||||
set(PROJECT_COPYRIGHT "Copyright (C) 2013-2015 ${PROJECT_COMPANYNAME} All Rights Reserved.")
|
||||
set(PROJECT_COMPANYNAME_DOMAIN "www.paralect.com")
|
||||
set(PROJECT_GITHUB_FORK "www.github.com/paralect/robomongo")
|
||||
set(PROJECT_GITHUB_ISSUES "www.github.com/paralect/robomongo/issues")
|
||||
|
||||
|
||||
@@ -125,15 +125,4 @@ Install Robomongo to `build/release/install` folder:
|
||||
Create package for your OS in `build/release/package` folder:
|
||||
|
||||
$ bin/pack
|
||||
|
||||
**Important Notes**
|
||||
- For Ubuntu 16.04 builds, it has been reported that Robomongo /bin/configure step might fail and installing mesa-common-dev package solves it. Details: https://github.com/paralect/robomongo/issues/1268
|
||||
|
||||
- For Centos builds, Robomongo /bin/configure step might fail due to error: `failed to find gl/gl.h`. In this case, the following packages must be installed:
|
||||
|
||||
```sh
|
||||
$ sudo yum install mesa-libGL
|
||||
$ sudo yum install mesa-libGL-devel
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -12,46 +12,19 @@ Runtime dependencies that are not privided by platforms but required by Robomong
|
||||
Diagnostic of dependencies
|
||||
--------------------------
|
||||
|
||||
#### Linux
|
||||
##### Linux
|
||||
|
||||
a. View dependencies of executable or shared library:
|
||||
View dependencies of executable or shared library:
|
||||
|
||||
$ ldd robomongo
|
||||
$ readelf -d robomongo
|
||||
|
||||
b. View dependency tree of executable or shared library:
|
||||
|
||||
$ lddtree robomongo
|
||||
$ ldd -v robomongo
|
||||
|
||||
c. View RPATH or RUNPATH records of executable or shared library:
|
||||
|
||||
View RPATH or RUNPATH records of executable or shared library:
|
||||
|
||||
$ objdump -x bin/robomongo | grep "RPATH\|RUNPATH"
|
||||
$ readelf -d bin/robomongo | grep RPATH
|
||||
|
||||
For Robomongo binary it should be `$ORIGIN/../lib`
|
||||
|
||||
d. Enable extensive logging for run-time shared library search
|
||||
|
||||
$ export LD_DEBUG=files
|
||||
$ bin/robomongo
|
||||
|
||||
Source:
|
||||
http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
|
||||
|
||||
e. Modify RPATH using `chrpath` and the dynamic linker and RPATH using paths `patchelf`
|
||||
|
||||
$ patchelf --set-rpath '$ORIGIN/../lib' robo
|
||||
|
||||
More: https://nixos.org/patchelf.html
|
||||
|
||||
$ chrpath -r "/somepath/lib/" robomongo
|
||||
|
||||
More:
|
||||
https://linux.die.net/man/1/chrpath
|
||||
http://www.programering.com/a/MTOwcDNwATU.html // examples
|
||||
|
||||
#### Mac OS X
|
||||
##### Mac OS X
|
||||
|
||||
Show dependencies of executable or shared library:
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 827 B After Width: | Height: | Size: 827 B |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
@@ -26,10 +26,10 @@ IDI_ICON1 ICON "@windows_icon@"
|
||||
BEGIN
|
||||
BLOCK "040904e4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "3T Software Labs Ltd\0"
|
||||
VALUE "CompanyName", "Paralect, Inc\0"
|
||||
VALUE "FileDescription", "Robomongo, MongoDB management tool\0"
|
||||
VALUE "FileVersion", VER_FILEVERSION_STR
|
||||
VALUE "LegalCopyright", "Copyright 3T Software Labs Ltd, 2014 - 2017\0"
|
||||
VALUE "LegalCopyright", "Copyright Paralect, 2013 - 2016\0"
|
||||
VALUE "ProductName", "Robomongo\0"
|
||||
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
|
||||
VALUE "OriginalFilename", "Robomongo.exe\0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Robomongo shortcut key reference
|
||||
================================
|
||||
"3T", "Robomongo"
|
||||
|
||||
### Windows/Linux users
|
||||
|
||||
Ctrl+Enter or F5 or Ctrl+R
|
||||
|
||||
@@ -53,16 +53,12 @@ set(SOURCES
|
||||
core/domain/App.cpp
|
||||
core/mongodb/MongoClient.cpp
|
||||
core/mongodb/MongoWorker.cpp
|
||||
core/mongodb/ReplicaSet.cpp
|
||||
core/settings/SettingsManager.cpp
|
||||
core/AppRegistry.cpp
|
||||
utils/string_operations.cpp
|
||||
utils/common.cpp
|
||||
|
||||
# Isolated Scope #3
|
||||
gui/GuiRegistry.cpp
|
||||
gui/dialogs/AboutDialog.cpp
|
||||
gui/dialogs/EulaDialog.cpp
|
||||
gui/dialogs/ConnectionAdvancedTab.cpp
|
||||
gui/dialogs/ConnectionAuthTab.cpp
|
||||
gui/dialogs/ConnectionBasicTab.cpp
|
||||
@@ -79,7 +75,6 @@ set(SOURCES
|
||||
# Isolated scope #4
|
||||
gui/dialogs/PreferencesDialog.cpp
|
||||
gui/dialogs/ConnectionsDialog.cpp
|
||||
gui/dialogs/CreateConnectionDialog.cpp
|
||||
gui/dialogs/ExportDialog.cpp
|
||||
|
||||
# Isolated scope #5
|
||||
@@ -92,7 +87,6 @@ set(SOURCES
|
||||
# Isolated scope #6
|
||||
gui/widgets/explorer/ExplorerCollectionTreeItem.cpp
|
||||
gui/widgets/explorer/ExplorerTreeItem.cpp
|
||||
gui/widgets/explorer/ExplorerReplicaSetFolderItem.cpp
|
||||
gui/widgets/explorer/ExplorerReplicaSetTreeItem.cpp
|
||||
gui/widgets/explorer/ExplorerDatabaseTreeItem.cpp
|
||||
gui/widgets/explorer/ExplorerDatabaseCategoryTreeItem.cpp
|
||||
@@ -124,7 +118,6 @@ set(SOURCES
|
||||
gui/widgets/workarea/QueryWidget.cpp
|
||||
gui/widgets/workarea/WorkAreaTabBar.cpp
|
||||
gui/widgets/workarea/WorkAreaTabWidget.cpp
|
||||
gui/widgets/workarea/WelcomeTab.cpp
|
||||
|
||||
# Final scope
|
||||
gui/widgets/LogWidget.cpp
|
||||
@@ -134,10 +127,9 @@ set(SOURCES
|
||||
gui/dialogs/SSLTab.cpp
|
||||
core/settings/SshSettings.cpp
|
||||
core/settings/SslSettings.cpp
|
||||
core/settings/ReplicaSetSettings.cpp
|
||||
core/settings/ReplicaSetSettings.cpp
|
||||
core/mongodb/SshTunnelWorker.cpp
|
||||
|
||||
resources/robo.qrc
|
||||
gui/resources/gui.qrc
|
||||
)
|
||||
|
||||
@@ -148,8 +140,6 @@ add_executable(robomongo MACOSX_BUNDLE WIN32 app/main.cpp ${SOURCES})
|
||||
target_link_libraries(robomongo
|
||||
PRIVATE
|
||||
Qt5::Widgets
|
||||
Qt5::Network
|
||||
Qt5::Xml
|
||||
qjson
|
||||
qscintilla
|
||||
mongodb
|
||||
@@ -171,8 +161,6 @@ target_compile_definitions(robomongo
|
||||
PROJECT_GITHUB_FORK="${PROJECT_GITHUB_FORK}"
|
||||
PROJECT_GITHUB_ISSUES="${PROJECT_GITHUB_ISSUES}"
|
||||
PROJECT_VERSION="${PROJECT_VERSION}"
|
||||
PROJECT_VERSION_SHORT="${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||
PROJECT_QT_VERSION="${Qt5Core_VERSION}"
|
||||
PROJECT_NAME_LOWERCASE="${PROJECT_NAME_LOWERCASE}")
|
||||
|
||||
if(SYSTEM_WINDOWS)
|
||||
@@ -203,18 +191,17 @@ elseif(SYSTEM_MACOSX)
|
||||
OUTPUT_NAME "Robomongo"
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/install/macosx/Info.plist.in"
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "Robomongo"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "com.3tsoftwarelabs.robomongo"
|
||||
MACOSX_BUNDLE_INFO_STRING "Robomongo ${PROJECT_VERSION}. Copyright 3T Software Labs Ltd, 2014 - 2017"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "com.paralect.Robomongo"
|
||||
MACOSX_BUNDLE_INFO_STRING "Robomongo ${PROJECT_VERSION}. Copyright Paralect, 2013 - 2016"
|
||||
MACOSX_BUNDLE_SHORT_VERSION "${PROJECT_VERSION}"
|
||||
MACOSX_BUNDLE_LONG_VERSION "${PROJECT_VERSION}"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}"
|
||||
MACOSX_BUNDLE_COPYRIGHT "Copyright 3T Software Labs Ltd, 2014 - 2017"
|
||||
MACOSX_BUNDLE_ICON_FILE "robomongo")
|
||||
MACOSX_BUNDLE_COPYRIGHT "Copyright Paralect, 2013 - 2016"
|
||||
MACOSX_BUNDLE_ICON_FILE "Robomongo")
|
||||
|
||||
elseif(SYSTEM_LINUX)
|
||||
set_target_properties(robomongo PROPERTIES
|
||||
INSTALL_RPATH "$ORIGIN/../lib"
|
||||
OUTPUT_NAME "robomongo")
|
||||
INSTALL_RPATH "$ORIGIN/../lib")
|
||||
endif()
|
||||
|
||||
# Install
|
||||
|
||||
@@ -10,18 +10,16 @@
|
||||
#include <mongo/base/initializer.h>
|
||||
#include <mongo/util/net/ssl_options.h>
|
||||
|
||||
#include "robomongo/core/AppRegistry.h"
|
||||
#include "robomongo/core/settings/SettingsManager.h"
|
||||
#include "robomongo/gui/MainWindow.h"
|
||||
#include "robomongo/gui/AppStyle.h"
|
||||
#include "robomongo/gui/dialogs/EulaDialog.h"
|
||||
#include "robomongo/ssh/ssh.h"
|
||||
|
||||
|
||||
int main(int argc, char *argv[], char** envp)
|
||||
{
|
||||
if (rbm_ssh_init())
|
||||
if (rbm_ssh_init()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Please check, do we really need envp for other OSes?
|
||||
#ifdef Q_OS_WIN
|
||||
@@ -56,25 +54,12 @@ int main(int argc, char *argv[], char** envp)
|
||||
app.setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
#endif
|
||||
|
||||
// EULA License Agreement
|
||||
auto const settingsManager = Robomongo::AppRegistry::instance().settingsManager();
|
||||
if (!settingsManager->acceptedEulaVersions().contains(PROJECT_VERSION)) {
|
||||
Robomongo::EulaDialog eulaDialog;
|
||||
if (eulaDialog.exec() == QDialog::Rejected) {
|
||||
rbm_ssh_cleanup();
|
||||
return 1;
|
||||
}
|
||||
// EULA accepted
|
||||
settingsManager->addAcceptedEulaVersion(PROJECT_VERSION);
|
||||
settingsManager->save();
|
||||
}
|
||||
|
||||
// Init GUI style
|
||||
Robomongo::AppStyleUtils::initStyle();
|
||||
|
||||
// Application main window
|
||||
Robomongo::MainWindow mainWindow;
|
||||
mainWindow.show();
|
||||
Robomongo::MainWindow win;
|
||||
win.show();
|
||||
|
||||
int rc = app.exec();
|
||||
rbm_ssh_cleanup();
|
||||
|
||||
@@ -32,18 +32,16 @@ namespace Robomongo
|
||||
typedef boost::shared_ptr<MongoDocument> MongoDocumentPtr;
|
||||
|
||||
enum ConnectionType {
|
||||
// This type of connection is shown in Explorer and also opens SSH tunnel for secondary
|
||||
// connections (if needed)
|
||||
// This type of connection is shown in Explorer and also
|
||||
// opens SSH tunnel for Secondary connections (if needed)
|
||||
ConnectionPrimary = 0,
|
||||
|
||||
// Never shown in Explorer and uses SSH tunnel from primary connection (if needed)
|
||||
// Never shown in Explorer and uses SSH tunnel from
|
||||
// Primary connection (if needed)
|
||||
ConnectionSecondary = 1,
|
||||
|
||||
// The same as Primary, but is specifically for testing connections.
|
||||
ConnectionTest = 2,
|
||||
|
||||
// Never shown in Explorer and can be used to refresh (via reconnecting) current connection view
|
||||
// (i.e. db version, storage engine, current replica set primary, status of replica set etc...)
|
||||
ConnectionRefresh = 3
|
||||
// The same as Primary, but is specifically for testing
|
||||
// connections.
|
||||
ConnectionTest = 2
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,35 +1,19 @@
|
||||
#include "robomongo/core/EventError.h"
|
||||
|
||||
#include "robomongo/utils/string_operations.h"
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
EventError::EventError() :
|
||||
_isNull(true) {}
|
||||
|
||||
EventError::EventError(const std::string &errorMessage, ErrorCode errorCode /*= Unknown*/,
|
||||
bool showErrorWindow /* = true */) :
|
||||
_errorMessage(captilizeFirstChar(errorMessage)),
|
||||
_errorCode(errorCode),
|
||||
_showErrorWindow(showErrorWindow),
|
||||
EventError::EventError(const std::string &errorMessage) :
|
||||
_errorMessage(errorMessage),
|
||||
_isNull(false) {}
|
||||
|
||||
EventError::EventError(const std::string &errorMessage, ReplicaSet const& replicaSetInfo,
|
||||
bool showErrorWindow /* = true */ ) :
|
||||
_errorMessage(errorMessage),
|
||||
_errorCode(SetPrimaryUnreachable),
|
||||
_replicaSetInfo(replicaSetInfo),
|
||||
_showErrorWindow(showErrorWindow),
|
||||
_isNull(false) {}
|
||||
|
||||
bool EventError::isNull() const
|
||||
{
|
||||
bool EventError::isNull() const {
|
||||
return _isNull;
|
||||
}
|
||||
|
||||
const std::string &EventError::errorMessage() const
|
||||
{
|
||||
const std::string &EventError::errorMessage() const {
|
||||
return _errorMessage;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#include "robomongo/core/mongodb/ReplicaSet.h"
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
/**
|
||||
@@ -12,11 +10,7 @@ namespace Robomongo
|
||||
*/
|
||||
class EventError
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
enum ErrorCode { Unknown, SetPrimaryUnreachable, ServerHasDifferentMembers };
|
||||
|
||||
/**
|
||||
* @brief Creates "null" (or, in other words, empty) error.
|
||||
* Subsequent call of isNull() on this object will return true.
|
||||
@@ -27,14 +21,7 @@ namespace Robomongo
|
||||
* @brief Creates error object with specified error message.
|
||||
* Subsequent call of isNull() on this object will return false.
|
||||
*/
|
||||
explicit EventError(const std::string &errorMessage, ErrorCode errorCode = Unknown,
|
||||
bool showErrorWindow = true);
|
||||
|
||||
/**
|
||||
* @brief Creates error object only for replica set connection failures
|
||||
*/
|
||||
explicit EventError(const std::string &errorMessage, ReplicaSet const& replicaSetInfo,
|
||||
bool showErrorWindow = true);
|
||||
explicit EventError(const std::string &errorMessage);
|
||||
|
||||
/**
|
||||
* @brief Tests whether error is "null" (or, in other words, empty).
|
||||
@@ -48,19 +35,13 @@ namespace Robomongo
|
||||
* @brief Returns error message that describes this error.
|
||||
*/
|
||||
const std::string &errorMessage() const;
|
||||
|
||||
ErrorCode errorCode() const { return _errorCode; }
|
||||
ReplicaSet replicaSetInfo() const { return _replicaSetInfo; }
|
||||
bool showErrorWindow() const { return _showErrorWindow; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Error message
|
||||
*/
|
||||
std::string const _errorMessage;
|
||||
ErrorCode const _errorCode = Unknown;
|
||||
ReplicaSet const _replicaSetInfo;
|
||||
bool const _showErrorWindow = true;
|
||||
bool const _isNull;
|
||||
const std::string _errorMessage;
|
||||
|
||||
bool _isNull;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "robomongo/core/domain/MongoShell.h"
|
||||
#include "robomongo/core/domain/MongoCollection.h"
|
||||
#include "robomongo/core/settings/ConnectionSettings.h"
|
||||
#include "robomongo/core/settings/ReplicaSetSettings.h"
|
||||
#include "robomongo/core/settings/SshSettings.h"
|
||||
#include "robomongo/core/settings/SslSettings.h"
|
||||
#include "robomongo/core/mongodb/SshTunnelWorker.h"
|
||||
@@ -106,7 +105,7 @@ namespace Robomongo
|
||||
* @param connection: ConnectionSettings, that will be owned by MongoServer.
|
||||
* @param visible: should this server be visible in UI (explorer) or not.
|
||||
*/
|
||||
MongoServer *App::openServerInternal(ConnectionSettings* connSettings, ConnectionType type) {
|
||||
MongoServer *App::openServerInternal(ConnectionSettings const* connection, ConnectionType type) {
|
||||
++_lastServerHandle;
|
||||
|
||||
if (type == ConnectionPrimary)
|
||||
@@ -114,16 +113,16 @@ namespace Robomongo
|
||||
|
||||
// When connection is SECONDARY or do not have
|
||||
// ssh settings enabled, continue without SSH Tunnel
|
||||
if (type == ConnectionSecondary || !connSettings->sshSettings()->enabled()) {
|
||||
return continueOpenServer(_lastServerHandle, connSettings, type);
|
||||
if (type == ConnectionSecondary || !connection->sshSettings()->enabled()) {
|
||||
return continueOpenServer(_lastServerHandle, connection, type);
|
||||
}
|
||||
|
||||
// Open SSH channel and only after that open connection
|
||||
LOG_MSG(QString("Creating SSH tunnel to %1:%2...")
|
||||
.arg(QtUtils::toQString(connSettings->sshSettings()->host()))
|
||||
.arg(connSettings->sshSettings()->port()), mongo::logger::LogSeverity::Info());
|
||||
.arg(QtUtils::toQString(connection->sshSettings()->host()))
|
||||
.arg(connection->sshSettings()->port()), mongo::logger::LogSeverity::Info());
|
||||
|
||||
ConnectionSettings* settingsCopy = connSettings->clone();
|
||||
ConnectionSettings* settingsCopy = connection->clone();
|
||||
SshTunnelWorker* sshWorker = new SshTunnelWorker(settingsCopy);
|
||||
_bus->send(sshWorker, new EstablishSshConnectionRequest(this, _lastServerHandle, sshWorker, settingsCopy, type));
|
||||
return NULL;
|
||||
@@ -135,8 +134,7 @@ namespace Robomongo
|
||||
*/
|
||||
void App::closeServer(MongoServer *server)
|
||||
{
|
||||
_servers.erase(std::remove_if(_servers.begin(), _servers.end(), stdutils::RemoveIfFound<MongoServer*>(server)),
|
||||
_servers.end());
|
||||
_servers.erase(std::remove_if(_servers.begin(), _servers.end(), stdutils::RemoveIfFound<MongoServer*>(server)), _servers.end());
|
||||
}
|
||||
|
||||
void App::openShell(MongoCollection *collection, const QString &filePathToSave)
|
||||
@@ -144,8 +142,7 @@ namespace Robomongo
|
||||
ConnectionSettings *connection = collection->database()->server()->connectionRecord();
|
||||
connection->setDefaultDatabase(collection->database()->name());
|
||||
QString script = detail::buildCollectionQuery(collection->name(), "find({})");
|
||||
openShell(collection->database()->server(), connection, ScriptInfo(script, true, CursorPosition(0, -2),
|
||||
QtUtils::toQString(collection->database()->name()), filePathToSave));
|
||||
openShell(connection, ScriptInfo(script, true, CursorPosition(0, -2), QtUtils::toQString(collection->database()->name()), filePathToSave));
|
||||
}
|
||||
|
||||
void App::openShell(MongoServer *server, const QString &script, const std::string &dbName,
|
||||
@@ -157,7 +154,7 @@ namespace Robomongo
|
||||
if (!dbName.empty())
|
||||
connection->setDefaultDatabase(dbName);
|
||||
|
||||
openShell(server, connection, ScriptInfo(script, execute, cursorPosition, shellName, filePathToSave));
|
||||
openShell(connection, ScriptInfo(script, execute, cursorPosition, shellName, filePathToSave));
|
||||
}
|
||||
|
||||
void App::openShell(MongoDatabase *database, const QString &script,
|
||||
@@ -166,19 +163,16 @@ namespace Robomongo
|
||||
{
|
||||
ConnectionSettings *connection = database->server()->connectionRecord();
|
||||
connection->setDefaultDatabase(database->name());
|
||||
openShell(database->server(), connection, ScriptInfo(script, execute, cursorPosition,
|
||||
shellName, filePathToSave));
|
||||
openShell(connection, ScriptInfo(script, execute, cursorPosition, shellName, filePathToSave));
|
||||
}
|
||||
|
||||
void App::openShell(MongoServer* server, ConnectionSettings* connection, const ScriptInfo &scriptInfo)
|
||||
void App::openShell(ConnectionSettings const* connection, const ScriptInfo &scriptInfo)
|
||||
{
|
||||
MongoServer *serverClone = openServerInternal(connection, ConnectionSecondary);
|
||||
if (!serverClone || !server)
|
||||
MongoServer *server = openServerInternal(connection, ConnectionSecondary);
|
||||
if (!server)
|
||||
return;
|
||||
|
||||
MongoShell *shell = new MongoShell(serverClone, scriptInfo);
|
||||
// Connection between explorer's server and tab's MongoShells
|
||||
_bus->subscribe(server, ReplicaSetRefreshed::Type, shell);
|
||||
MongoShell *shell = new MongoShell(server, scriptInfo);
|
||||
_shells.push_back(shell);
|
||||
_bus->publish(new OpeningShellEvent(this, shell));
|
||||
shell->execute();
|
||||
@@ -201,33 +195,22 @@ namespace Robomongo
|
||||
delete shell;
|
||||
}
|
||||
|
||||
MongoServer *App::continueOpenServer(int serverHandle, ConnectionSettings* connSettings, ConnectionType type,
|
||||
int localport)
|
||||
{
|
||||
ConnectionSettings* connSettingsClone = connSettings->clone();
|
||||
MongoServer *App::continueOpenServer(int serverHandle, ConnectionSettings const* connection, ConnectionType type, int localport) {
|
||||
ConnectionSettings* settings = connection->clone();
|
||||
|
||||
// Modify connection settings when SSH tunnel is used
|
||||
if ((type == ConnectionPrimary || type == ConnectionTest)
|
||||
&& connSettingsClone->sshSettings()->enabled()) {
|
||||
connSettingsClone->setServerHost("127.0.0.1");
|
||||
connSettingsClone->setServerPort(localport);
|
||||
&& settings->sshSettings()->enabled()) {
|
||||
settings->setServerHost("127.0.0.1");
|
||||
settings->setServerPort(localport);
|
||||
}
|
||||
|
||||
MongoServer *server = new MongoServer(serverHandle, connSettingsClone, type);
|
||||
MongoServer *server = new MongoServer(serverHandle, settings, type);
|
||||
_servers.push_back(server);
|
||||
|
||||
server->runWorkerThread();
|
||||
|
||||
auto replicaSetStr = QString::fromStdString(connSettings->connectionName()) + " [Replica Set]";
|
||||
replicaSetStr = (connSettings->replicaSetSettings()->members().size() > 0)
|
||||
? replicaSetStr + QString::fromStdString(connSettings->replicaSetSettings()->members()[0])
|
||||
: replicaSetStr + "";
|
||||
|
||||
QString serverAddress = connSettings->isReplicaSet()
|
||||
? replicaSetStr
|
||||
: QString::fromStdString(connSettings->getFullAddress());
|
||||
|
||||
LOG_MSG(QString("Connecting to %1...").arg(serverAddress), mongo::logger::LogSeverity::Info());
|
||||
LOG_MSG(QString("Connecting to %1...").arg(QtUtils::toQString(server->connectionRecord()->getFullAddress())), mongo::logger::LogSeverity::Info());
|
||||
server->tryConnect();
|
||||
return server;
|
||||
}
|
||||
@@ -273,6 +256,7 @@ namespace Robomongo
|
||||
_bus->publish(new ConnectionFailedEvent(this, serverHandle, type, errormsg, reason));
|
||||
}
|
||||
|
||||
|
||||
bool App::askSslPassphrasePromptDialog(ConnectionSettings *connSettings) const
|
||||
{
|
||||
auto sslSettings = connSettings->sslSettings();
|
||||
|
||||
@@ -70,11 +70,7 @@ namespace Robomongo
|
||||
bool execute = true, const QString &shellName = QString(),
|
||||
const CursorPosition &cursorPosition = CursorPosition(), const QString &filePathToSave = QString());
|
||||
|
||||
/**
|
||||
* @brief Open new shell using explorer's MongoServer (ExplorerServerTreeItem's _server)
|
||||
*/
|
||||
void openShell(MongoServer* server, ConnectionSettings* connSettings, const ScriptInfo &scriptInfo);
|
||||
|
||||
void openShell(ConnectionSettings const* connection, const ScriptInfo &scriptInfo);
|
||||
MongoServersContainerType getServers() const { return _servers; };
|
||||
|
||||
/**
|
||||
@@ -93,8 +89,8 @@ namespace Robomongo
|
||||
void handle(LogEvent *event);
|
||||
|
||||
private:
|
||||
MongoServer *openServerInternal(ConnectionSettings* connSettings, ConnectionType type);
|
||||
MongoServer *continueOpenServer(int serverHandle, ConnectionSettings* connSettings, ConnectionType type, int localport = 0);
|
||||
MongoServer *openServerInternal(ConnectionSettings const* connection, ConnectionType type);
|
||||
MongoServer *continueOpenServer(int serverHandle, ConnectionSettings const *connection, ConnectionType type, int localport = 0);
|
||||
|
||||
/**
|
||||
* @brief Create prompt dialog to enter SSL PEM key passphrase and save passphrase into SSL settings
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include "robomongo/core/mongodb/MongoWorker.h"
|
||||
#include "robomongo/core/AppRegistry.h"
|
||||
#include "robomongo/core/EventBus.h"
|
||||
#include "robomongo/core/utils/Logger.h"
|
||||
#include "robomongo/utils/common.h"
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
@@ -39,148 +37,115 @@ namespace Robomongo
|
||||
void MongoDatabase::loadCollections()
|
||||
{
|
||||
_bus->publish(new MongoDatabaseCollectionsLoadingEvent(this));
|
||||
_bus->send(_server->worker(), new LoadCollectionNamesRequest(this, _name));
|
||||
_bus->send(_server->client(), new LoadCollectionNamesRequest(this, _name));
|
||||
}
|
||||
|
||||
void MongoDatabase::loadUsers()
|
||||
{
|
||||
_bus->publish(new MongoDatabaseUsersLoadingEvent(this));
|
||||
_bus->send(_server->worker(), new LoadUsersRequest(this, _name));
|
||||
_bus->send(_server->client(), new LoadUsersRequest(this, _name));
|
||||
}
|
||||
|
||||
void MongoDatabase::loadFunctions()
|
||||
{
|
||||
_bus->publish(new MongoDatabaseFunctionsLoadingEvent(this));
|
||||
_bus->send(_server->worker(), new LoadFunctionsRequest(this, _name));
|
||||
_bus->send(_server->client(), new LoadFunctionsRequest(this, _name));
|
||||
}
|
||||
|
||||
void MongoDatabase::createCollection(const std::string &collection, long long size, bool capped, int maxDocNum, const mongo::BSONObj& extraOptions)
|
||||
{
|
||||
_bus->send(_server->worker(),
|
||||
_bus->send(_server->client(),
|
||||
new CreateCollectionRequest(this, MongoNamespace(_name, collection), extraOptions, size, capped, maxDocNum));
|
||||
}
|
||||
|
||||
void MongoDatabase::dropCollection(const std::string &collection)
|
||||
{
|
||||
_bus->send(_server->worker(), new DropCollectionRequest(this, MongoNamespace(_name, collection)));
|
||||
_bus->send(_server->client(), new DropCollectionRequest(this, MongoNamespace(_name, collection)));
|
||||
}
|
||||
|
||||
void MongoDatabase::renameCollection(const std::string &collection, const std::string &newCollection)
|
||||
{
|
||||
_bus->send(_server->worker(), new RenameCollectionRequest(this, MongoNamespace(_name, collection),
|
||||
newCollection));
|
||||
_bus->send(_server->client(), new RenameCollectionRequest(this, MongoNamespace(_name, collection), newCollection));
|
||||
}
|
||||
|
||||
void MongoDatabase::duplicateCollection(const std::string &collection, const std::string &newCollection)
|
||||
{
|
||||
_bus->send(_server->worker(), new DuplicateCollectionRequest(this, MongoNamespace(_name, collection), newCollection));
|
||||
_bus->send(_server->client(), new DuplicateCollectionRequest(this, MongoNamespace(_name, collection), newCollection));
|
||||
}
|
||||
|
||||
void MongoDatabase::copyCollection(MongoServer *server, const std::string &sourceDatabase, const std::string &collection)
|
||||
{
|
||||
_bus->send(_server->worker(), new CopyCollectionToDiffServerRequest(this, server->worker(), sourceDatabase, collection, _name));
|
||||
_bus->send(_server->client(), new CopyCollectionToDiffServerRequest(this, server->client(), sourceDatabase, collection, _name));
|
||||
}
|
||||
|
||||
void MongoDatabase::createUser(const MongoUser &user, bool overwrite)
|
||||
{
|
||||
_bus->send(_server->worker(), new CreateUserRequest(this, _name, user, overwrite));
|
||||
_bus->send(_server->client(), new CreateUserRequest(this, _name, user, overwrite));
|
||||
}
|
||||
|
||||
void MongoDatabase::dropUser(const mongo::OID &id, std::string const& userName)
|
||||
void MongoDatabase::dropUser(const mongo::OID &id)
|
||||
{
|
||||
_bus->send(_server->worker(), new DropUserRequest(this, _name, id, userName));
|
||||
_bus->send(_server->client(), new DropUserRequest(this, _name, id));
|
||||
}
|
||||
|
||||
void MongoDatabase::createFunction(const MongoFunction &fun)
|
||||
{
|
||||
_bus->send(_server->worker(), new CreateFunctionRequest(this, _name, fun));
|
||||
_bus->send(_server->client(), new CreateFunctionRequest(this, _name, fun));
|
||||
}
|
||||
|
||||
void MongoDatabase::updateFunction(const std::string &name, const MongoFunction &fun)
|
||||
{
|
||||
_bus->send(_server->worker(), new CreateFunctionRequest(this, _name, fun, name));
|
||||
_bus->send(_server->client(), new CreateFunctionRequest(this, _name, fun, name));
|
||||
}
|
||||
|
||||
void MongoDatabase::dropFunction(const std::string &name)
|
||||
{
|
||||
_bus->send(_server->worker(), new DropFunctionRequest(this, _name, name));
|
||||
_bus->send(_server->client(), new DropFunctionRequest(this, _name, name));
|
||||
}
|
||||
|
||||
void MongoDatabase::handle(LoadCollectionNamesResponse *event)
|
||||
void MongoDatabase::handle(LoadCollectionNamesResponse *loaded)
|
||||
{
|
||||
if (event->isError()) {
|
||||
if (_server->connectionRecord()->isReplicaSet()) // replica set
|
||||
handleIfReplicaSetUnreachable(event);
|
||||
else // single server
|
||||
_bus->publish(new MongoDatabaseCollectionListLoadedEvent(this, event->error()));
|
||||
|
||||
genericEventErrorHandler(event, "Failed to refresh 'Collections'.", _bus, this);
|
||||
if (loaded->isError()) {
|
||||
_bus->publish(new MongoDatabaseCollectionListLoadedEvent(this, loaded->error()));
|
||||
return;
|
||||
}
|
||||
|
||||
clearCollections();
|
||||
|
||||
for (auto const& collectionInfo : event->collectionInfos())
|
||||
addCollection(new MongoCollection(this, collectionInfo));
|
||||
const std::vector<MongoCollectionInfo> &colectionsInfos = loaded->collectionInfos();
|
||||
for (std::vector<MongoCollectionInfo>::const_iterator it = colectionsInfos.begin(); it != colectionsInfos.end(); ++it) {
|
||||
const MongoCollectionInfo &info = *it;
|
||||
MongoCollection *collection = new MongoCollection(this, info);
|
||||
addCollection(collection);
|
||||
}
|
||||
|
||||
_bus->publish(new MongoDatabaseCollectionListLoadedEvent(this, _collections));
|
||||
LOG_MSG("'Collections' refreshed.", mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
|
||||
void MongoDatabase::handle(CreateFunctionResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
handleIfReplicaSetUnreachable(event);
|
||||
genericEventErrorHandler(event, "Failed to create function \'" + event->functionName + "\'.", _bus, this);
|
||||
}
|
||||
else {
|
||||
loadFunctions();
|
||||
LOG_MSG("Function \'" + event->functionName + "\' created.", mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
}
|
||||
|
||||
void MongoDatabase::handle(CreateUserResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
handleIfReplicaSetUnreachable(event);
|
||||
genericEventErrorHandler(event, "Failed to create user \'" + event->userName + "\'.", _bus, this);
|
||||
}
|
||||
else {
|
||||
loadUsers();
|
||||
LOG_MSG("User \'" + event->userName + "\' created.", mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
if (event->isError())
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
void MongoDatabase::handle(LoadUsersResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
if (_server->connectionRecord()->isReplicaSet()) // replica set
|
||||
handleIfReplicaSetUnreachable(event);
|
||||
else // single server
|
||||
_bus->publish(new MongoDatabaseUsersLoadedEvent(this, event->error()));
|
||||
|
||||
genericEventErrorHandler(event, "Failed to refresh 'Users'.", _bus, this);
|
||||
_bus->publish(new MongoDatabaseUsersLoadedEvent(this, event->error()));
|
||||
return;
|
||||
}
|
||||
|
||||
_bus->publish(new MongoDatabaseUsersLoadedEvent(this, this, event->users()));
|
||||
LOG_MSG("'Users' refreshed.", mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
|
||||
void MongoDatabase::handle(LoadFunctionsResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
if (_server->connectionRecord()->isReplicaSet()) // replica set
|
||||
handleIfReplicaSetUnreachable(event);
|
||||
else // single server
|
||||
_bus->publish(new MongoDatabaseFunctionsLoadedEvent(this, event->error()));
|
||||
|
||||
genericEventErrorHandler(event, "Failed to refresh 'Functions'.", _bus, this);
|
||||
_bus->publish(new MongoDatabaseFunctionsLoadedEvent(this, event->error()));
|
||||
return;
|
||||
}
|
||||
|
||||
_bus->publish(new MongoDatabaseFunctionsLoadedEvent(this, this, event->functions()));
|
||||
LOG_MSG("'Functions' refreshed.", mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
|
||||
void MongoDatabase::clearCollections()
|
||||
@@ -194,91 +159,18 @@ namespace Robomongo
|
||||
_collections.push_back(collection);
|
||||
}
|
||||
|
||||
void MongoDatabase::handle(CreateCollectionResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
handleIfReplicaSetUnreachable(event);
|
||||
genericEventErrorHandler(event, "Failed to create collection \'" + event->collection + "\'.", _bus, this);
|
||||
}
|
||||
else {
|
||||
loadCollections();
|
||||
LOG_MSG("Collection \'" + event->collection + "\' created.", mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
void MongoDatabase::handle(CreateCollectionResponse *event) {
|
||||
genericResponseHandler(event, "Failed to create collection.");
|
||||
}
|
||||
|
||||
void MongoDatabase::handle(DropCollectionResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
handleIfReplicaSetUnreachable(event);
|
||||
genericEventErrorHandler(event, "Failed to drop collection \'" + event->collection + "\'.", _bus, this);
|
||||
}
|
||||
else {
|
||||
loadCollections();
|
||||
LOG_MSG("Collection \'" + event->collection + "\' dropped", mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
void MongoDatabase::handle(DropCollectionResponse *event) {
|
||||
genericResponseHandler(event, "Failed to drop collection.");
|
||||
}
|
||||
|
||||
|
||||
void MongoDatabase::handle(DropFunctionResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
handleIfReplicaSetUnreachable(event);
|
||||
genericEventErrorHandler(event, "Failed to remove function \'" + event->functionName + "\'.", _bus, this);
|
||||
}
|
||||
else {
|
||||
loadFunctions();
|
||||
LOG_MSG("Function \'" + event->functionName + "\' removed", mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
}
|
||||
|
||||
void MongoDatabase::handle(DropUserResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
handleIfReplicaSetUnreachable(event);
|
||||
genericEventErrorHandler(event, "Failed to drop user \'" + event->username + "\'.", _bus, this);
|
||||
}
|
||||
else {
|
||||
loadUsers();
|
||||
LOG_MSG("User \'" + event->username + "\' dropped", mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
}
|
||||
|
||||
void MongoDatabase::handle(RenameCollectionResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
handleIfReplicaSetUnreachable(event);
|
||||
genericEventErrorHandler(event, "Failed to rename collection.", _bus, this);
|
||||
}
|
||||
else {
|
||||
loadCollections();
|
||||
LOG_MSG("Collection \'" + event->oldCollection + "\' renamed to \'" +
|
||||
event->newCollection +"\'." , mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
}
|
||||
|
||||
void MongoDatabase::handle(DuplicateCollectionResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
handleIfReplicaSetUnreachable(event);
|
||||
genericEventErrorHandler(event, "Failed to duplicate collection \'" + event->sourceCollection + "\'.",
|
||||
_bus, this);
|
||||
}
|
||||
else {
|
||||
loadCollections();
|
||||
LOG_MSG("Collection \'" + event->sourceCollection + "\' duplicated as \'" +
|
||||
event->duplicateCollection + "\'.", mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
}
|
||||
|
||||
void MongoDatabase::handleIfReplicaSetUnreachable(Event *event)
|
||||
{
|
||||
if (!_server->connectionRecord()->isReplicaSet())
|
||||
void MongoDatabase::genericResponseHandler(Event *event, const std::string &userFriendlyMessage) {
|
||||
if (!event->isError())
|
||||
return;
|
||||
|
||||
if (EventError::SetPrimaryUnreachable == event->error().errorCode()) {
|
||||
auto refreshEvent = ReplicaSetRefreshed(this, event->error(), event->error().replicaSetInfo());
|
||||
_server->handle(&refreshEvent);
|
||||
}
|
||||
_bus->publish(new OperationFailedEvent(this, event->error().errorMessage(), userFriendlyMessage));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Robomongo
|
||||
void copyCollection(MongoServer *server, const std::string &sourceDatabase, const std::string &collection);
|
||||
|
||||
void createUser(const MongoUser &user, bool overwrite);
|
||||
void dropUser(const mongo::OID &id, std::string const& userName);
|
||||
void dropUser(const mongo::OID &id);
|
||||
|
||||
void createFunction(const MongoFunction &fun);
|
||||
void updateFunction(const std::string &name, const MongoFunction &fun);
|
||||
@@ -83,19 +83,14 @@ namespace Robomongo
|
||||
void handle(LoadCollectionNamesResponse *event);
|
||||
void handle(LoadUsersResponse *event);
|
||||
void handle(LoadFunctionsResponse *event);
|
||||
void handle(CreateFunctionResponse *event);
|
||||
void handle(CreateUserResponse *event);
|
||||
void handle(CreateCollectionResponse *event);
|
||||
void handle(DropCollectionResponse *event);
|
||||
void handle(DropFunctionResponse *event);
|
||||
void handle(DropUserResponse *event);
|
||||
void handle(RenameCollectionResponse *event);
|
||||
void handle(DuplicateCollectionResponse *event);
|
||||
|
||||
private:
|
||||
void clearCollections();
|
||||
void addCollection(MongoCollection *collection);
|
||||
void handleIfReplicaSetUnreachable(Event *event);
|
||||
void genericResponseHandler(Event *event, const std::string &userFriendlyMessage);
|
||||
|
||||
private:
|
||||
MongoServer *_server;
|
||||
|
||||
@@ -4,17 +4,12 @@
|
||||
#include "robomongo/core/settings/ConnectionSettings.h"
|
||||
#include "robomongo/core/settings/SshSettings.h"
|
||||
#include "robomongo/core/settings/SettingsManager.h"
|
||||
#include "robomongo/core/settings/ReplicaSetSettings.h"
|
||||
#include "robomongo/core/mongodb/MongoWorker.h"
|
||||
#include "robomongo/core/mongodb/SshTunnelWorker.h"
|
||||
#include "robomongo/core/AppRegistry.h"
|
||||
#include "robomongo/core/domain/App.h"
|
||||
#include "robomongo/core/EventBus.h"
|
||||
#include "robomongo/core/events/MongoEventsInfo.h"
|
||||
#include "robomongo/core/utils/Logger.h"
|
||||
#include "robomongo/core/utils/QtUtils.h"
|
||||
#include "robomongo/utils/common.h"
|
||||
#include "robomongo/utils/string_operations.h"
|
||||
|
||||
namespace Robomongo {
|
||||
R_REGISTER_EVENT(MongoServerLoadingDatabasesEvent)
|
||||
@@ -22,64 +17,45 @@ namespace Robomongo {
|
||||
MongoServer::MongoServer(int handle, ConnectionSettings *settings, ConnectionType connectionType) : QObject(),
|
||||
_version(0.0f),
|
||||
_connectionType(connectionType),
|
||||
_worker(nullptr),
|
||||
_client(NULL),
|
||||
_isConnected(false),
|
||||
_connSettings(settings),
|
||||
_settings(settings),
|
||||
_handle(handle),
|
||||
_bus(AppRegistry::instance().bus()),
|
||||
_app(AppRegistry::instance().app()),
|
||||
_replicaSetInfo(nullptr)
|
||||
{}
|
||||
_app(AppRegistry::instance().app()) { }
|
||||
|
||||
bool MongoServer::isConnected() const {
|
||||
return _isConnected;
|
||||
}
|
||||
|
||||
ConnectionSettings *MongoServer::connectionRecord() const {
|
||||
return _connSettings.get();
|
||||
return _settings;
|
||||
}
|
||||
|
||||
MongoServer::~MongoServer() {
|
||||
clearDatabases();
|
||||
|
||||
if (_worker) {
|
||||
_worker->stopAndDelete();
|
||||
if (_client != NULL) {
|
||||
_client->stopAndDelete();
|
||||
}
|
||||
|
||||
// MongoWorker "_worker" is not deleted here, because it is now owned by
|
||||
// MongoWorker "_client" does not deleted here, because it is now owned by
|
||||
// another thread (call to moveToThread() made in MongoWorker constructor).
|
||||
// It will be deleted by this thread by means of "deleteLater()", which
|
||||
// is also specified in MongoWorker constructor.
|
||||
|
||||
delete _settings;
|
||||
}
|
||||
|
||||
void MongoServer::tryConnect()
|
||||
{
|
||||
_bus->send(_worker, new EstablishConnectionRequest(this, _connectionType, _connSettings->uuid().toStdString()));
|
||||
/**
|
||||
* @brief Try to connect to MongoDB server.
|
||||
* @throws MongoException, if fails
|
||||
*/
|
||||
void MongoServer::tryConnect() {
|
||||
_bus->send(_client, new EstablishConnectionRequest(this, _connectionType));
|
||||
}
|
||||
|
||||
void MongoServer::tryRefresh()
|
||||
{
|
||||
_bus->send(_worker, new EstablishConnectionRequest(this, ConnectionRefresh, _connSettings->uuid().toStdString()));
|
||||
}
|
||||
|
||||
void MongoServer::tryRefreshReplicaSetConnection()
|
||||
{
|
||||
_bus->send(_worker, new EstablishConnectionRequest(this, ConnectionRefresh, _connSettings->uuid().toStdString()));
|
||||
}
|
||||
|
||||
void MongoServer::tryRefreshReplicaSetFolder(bool expanded, bool showLoading /*= true*/)
|
||||
{
|
||||
if (!_connSettings->isReplicaSet())
|
||||
return;
|
||||
|
||||
if (showLoading)
|
||||
_bus->publish(new ReplicaSetFolderLoading(this));
|
||||
|
||||
_bus->send(_worker, new RefreshReplicaSetFolderRequest(this, expanded));
|
||||
}
|
||||
|
||||
QStringList MongoServer::getDatabasesNames() const
|
||||
{
|
||||
QStringList MongoServer::getDatabasesNames() const {
|
||||
QStringList result;
|
||||
for (QList<MongoDatabase *>::const_iterator it = _databases.begin(); it != _databases.end(); ++it) {
|
||||
MongoDatabase *datab = *it;
|
||||
@@ -88,17 +64,11 @@ namespace Robomongo {
|
||||
return result;
|
||||
}
|
||||
|
||||
void MongoServer::addDatabase(MongoDatabase *database) {
|
||||
_databases.append(database);
|
||||
void MongoServer::createDatabase(const std::string &dbName) {
|
||||
_bus->send(_client, new CreateDatabaseRequest(this, dbName));
|
||||
}
|
||||
|
||||
void MongoServer::createDatabase(const std::string &dbName)
|
||||
{
|
||||
_bus->send(_worker, new CreateDatabaseRequest(this, dbName));
|
||||
}
|
||||
|
||||
MongoDatabase *MongoServer::findDatabaseByName(const std::string &dbName) const
|
||||
{
|
||||
MongoDatabase *MongoServer::findDatabaseByName(const std::string &dbName) const {
|
||||
for (QList<MongoDatabase *>::const_iterator it = _databases.begin(); it != _databases.end(); ++it) {
|
||||
MongoDatabase *datab = *it;
|
||||
if (datab->name() == dbName) {
|
||||
@@ -109,7 +79,7 @@ namespace Robomongo {
|
||||
}
|
||||
|
||||
void MongoServer::dropDatabase(const std::string &dbName) {
|
||||
_bus->send(_worker, new DropDatabaseRequest(this, dbName));
|
||||
_bus->send(_client, new DropDatabaseRequest(this, dbName));
|
||||
}
|
||||
|
||||
void MongoServer::insertDocuments(const std::vector<mongo::BSONObj> &objCont,
|
||||
@@ -120,7 +90,7 @@ namespace Robomongo {
|
||||
}
|
||||
|
||||
void MongoServer::insertDocument(const mongo::BSONObj &obj, const MongoNamespace &ns) {
|
||||
_bus->send(_worker, new InsertDocumentRequest(this, obj, ns));
|
||||
_bus->send(_client, new InsertDocumentRequest(this, obj, ns));
|
||||
}
|
||||
|
||||
void MongoServer::saveDocuments(const std::vector<mongo::BSONObj> &objCont, const MongoNamespace &ns) {
|
||||
@@ -130,315 +100,33 @@ namespace Robomongo {
|
||||
}
|
||||
|
||||
void MongoServer::saveDocument(const mongo::BSONObj &obj, const MongoNamespace &ns) {
|
||||
_bus->send(_worker, new InsertDocumentRequest(this, obj, ns, true));
|
||||
_bus->send(_client, new InsertDocumentRequest(this, obj, ns, true));
|
||||
}
|
||||
|
||||
void MongoServer::removeDocuments(mongo::Query query, const MongoNamespace &ns,
|
||||
RemoveDocumentCount removeCount, int index)
|
||||
{
|
||||
_bus->send(_worker, new RemoveDocumentRequest(this, query, ns, removeCount, index));
|
||||
void MongoServer::removeDocuments(mongo::Query query, const MongoNamespace &ns, bool justOne) {
|
||||
_bus->send(_client, new RemoveDocumentRequest(this, query, ns, justOne));
|
||||
}
|
||||
|
||||
void MongoServer::loadDatabases()
|
||||
{
|
||||
void MongoServer::loadDatabases() {
|
||||
_bus->publish(new MongoServerLoadingDatabasesEvent(this));
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
tryRefreshReplicaSetConnection();
|
||||
}
|
||||
else { // single server
|
||||
_bus->send(_worker, new LoadDatabaseNamesRequest(this));
|
||||
}
|
||||
_bus->send(_client, new LoadDatabaseNamesRequest(this));
|
||||
}
|
||||
|
||||
void MongoServer::clearDatabases()
|
||||
{
|
||||
void MongoServer::clearDatabases() {
|
||||
qDeleteAll(_databases);
|
||||
_databases.clear();
|
||||
}
|
||||
|
||||
void MongoServer::handle(EstablishConnectionResponse *event)
|
||||
{
|
||||
_connectionType = event->connectionType;
|
||||
void MongoServer::addDatabase(MongoDatabase *database) {
|
||||
_databases.append(database);
|
||||
}
|
||||
|
||||
// In any case, replica set info must be updated, there might be reachable secondary(ies).
|
||||
// Also cached set name must be updated or cleared for failed connections.
|
||||
updateReplicaSetSettings(event);
|
||||
|
||||
// --- Connection Failed
|
||||
void MongoServer::handle(EstablishConnectionResponse *event) {
|
||||
if (event->isError()) {
|
||||
handleConnectionFailure(event);
|
||||
return;
|
||||
}
|
||||
_isConnected = false;
|
||||
|
||||
// --- Connections Successful
|
||||
// Save various information after successful connection
|
||||
const ConnectionInfo &info = event->info;
|
||||
_version = info._version;
|
||||
_storageEngineType = info._storageEngineType;
|
||||
_isConnected = true;
|
||||
|
||||
// ConnectionRefresh is used just to update connection view (_version, _storageEngineType, _repPrimary etc..)
|
||||
// So we return here after updating(refreshing) information related to connection view.
|
||||
if (ConnectionRefresh == event->connectionType) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
// If it is replica set connection, do not return yet.
|
||||
LOG_MSG("Replica set refreshed. [" + _connSettings->connectionName() + ']',
|
||||
mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
else { // single server
|
||||
LOG_MSG("Server refreshed.", mongo::logger::LogSeverity::Info());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Only for single servers
|
||||
if (!_connSettings->isReplicaSet()) {
|
||||
_bus->publish(new ConnectionEstablishedEvent(this, _connectionType, info));
|
||||
// Do nothing if this is not a "primary" connection
|
||||
if (ConnectionPrimary != _connectionType)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConnectionPrimary == _connectionType)
|
||||
LOG_MSG("Establish connection successful. Connection: " + _connSettings->connectionName(),
|
||||
mongo::logger::LogSeverity::Info());
|
||||
|
||||
clearDatabases();
|
||||
for (auto const& dbname : info._databases) {
|
||||
MongoDatabase *db = new MongoDatabase(this, dbname);
|
||||
addDatabase(db); // todo: serverClones for replica sets should not do this
|
||||
}
|
||||
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
_bus->publish(new ConnectionEstablishedEvent(this, event->connectionType, info));
|
||||
// In order to do first connection much faster, time consuming refresh
|
||||
// "repSetMonitor->startOrContinueRefresh(). refreshAll()" is being requested after
|
||||
// successful connection.
|
||||
if (ConnectionPrimary == event->connectionType)
|
||||
_bus->send(_worker, new RefreshReplicaSetFolderRequest(this, false));
|
||||
}
|
||||
}
|
||||
|
||||
void MongoServer::handle(RefreshReplicaSetFolderResponse *event)
|
||||
{
|
||||
handleReplicaSetRefreshEvents(event->isError(), event->error(), event->replicaSet, event->expanded);
|
||||
}
|
||||
|
||||
void MongoServer::handle(LoadDatabaseNamesResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
_bus->publish(new DatabaseListLoadedEvent(this, event->error()));
|
||||
return;
|
||||
}
|
||||
|
||||
clearDatabases();
|
||||
|
||||
for (auto const& dbname : event->databaseNames) {
|
||||
MongoDatabase *db = new MongoDatabase(this, dbname);
|
||||
addDatabase(db);
|
||||
}
|
||||
|
||||
_bus->publish(new DatabaseListLoadedEvent(this, _databases));
|
||||
LOG_MSG("Database list refreshed. Connection: " + _connSettings->connectionName(),
|
||||
mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
|
||||
void MongoServer::handle(InsertDocumentResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
if (ConnectionPrimary == _connectionType) { // Insert document from explorer context menu
|
||||
if (EventError::SetPrimaryUnreachable == event->error().errorCode()) {
|
||||
auto refreshEvent = ReplicaSetRefreshed(this, event->error(), event->error().replicaSetInfo());
|
||||
handle(&refreshEvent);
|
||||
}
|
||||
}
|
||||
else { // Insert document from tab results window (Notifier, OutputWindow widget)
|
||||
_bus->publish(new InsertDocumentResponse(this, event->error()));
|
||||
}
|
||||
}
|
||||
genericEventErrorHandler(event, "Failed to insert document.", _bus, this);
|
||||
}
|
||||
else {
|
||||
_bus->publish(new InsertDocumentResponse(this, event->error()));
|
||||
LOG_MSG("Document inserted.", mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MongoServer::handle(RemoveDocumentResponse *event)
|
||||
{
|
||||
if (event->removeCount == RemoveDocumentCount::MULTI && event->index > 0)
|
||||
return;
|
||||
|
||||
std::string subStr;
|
||||
switch (event->removeCount) {
|
||||
case RemoveDocumentCount::ONE: subStr = "document."; break;
|
||||
case RemoveDocumentCount::MULTI: subStr = "documents."; break;
|
||||
case RemoveDocumentCount::ALL: subStr = "all documents."; break;
|
||||
default: subStr = "(logic error)."; break;
|
||||
}
|
||||
|
||||
if (event->isError()) {
|
||||
if (_connSettings->isReplicaSet() &&
|
||||
EventError::SetPrimaryUnreachable == event->error().errorCode()) {
|
||||
auto refreshEvent = ReplicaSetRefreshed(this, event->error(), event->error().replicaSetInfo());
|
||||
handle(&refreshEvent);
|
||||
}
|
||||
genericEventErrorHandler(event, "Failed to remove " + subStr, _bus, this);
|
||||
}
|
||||
else { // success
|
||||
_bus->publish(new RemoveDocumentResponse(this, event->error(), event->removeCount, event->index));
|
||||
LOG_MSG("Removed " + subStr, mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
}
|
||||
|
||||
void MongoServer::runWorkerThread()
|
||||
{
|
||||
_worker = new MongoWorker(_connSettings->clone(),
|
||||
AppRegistry::instance().settingsManager()->loadMongoRcJs(),
|
||||
AppRegistry::instance().settingsManager()->batchSize(),
|
||||
AppRegistry::instance().settingsManager()->mongoTimeoutSec(),
|
||||
AppRegistry::instance().settingsManager()->shellTimeoutSec());
|
||||
}
|
||||
|
||||
void MongoServer::handle(CreateDatabaseResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
if (_connSettings->isReplicaSet() &&
|
||||
EventError::SetPrimaryUnreachable == event->error().errorCode()) {
|
||||
auto refreshEvent = ReplicaSetRefreshed(this, event->error(), event->error().replicaSetInfo());
|
||||
handle(&refreshEvent);
|
||||
}
|
||||
genericEventErrorHandler(event, "Failed to create database \'" + event->database + "\'.", _bus, this);
|
||||
}
|
||||
else {
|
||||
loadDatabases();
|
||||
LOG_MSG("Database \'" + event->database + "\' created.", mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
}
|
||||
|
||||
void MongoServer::handle(DropDatabaseResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
if (_connSettings->isReplicaSet() &&
|
||||
EventError::SetPrimaryUnreachable == event->error().errorCode()) {
|
||||
auto refreshEvent = ReplicaSetRefreshed(this, event->error(), event->error().replicaSetInfo());
|
||||
handle(&refreshEvent);
|
||||
}
|
||||
genericEventErrorHandler(event, "Failed to drop database \'" + event->database + "\'.", _bus, this);
|
||||
}
|
||||
else {
|
||||
loadDatabases();
|
||||
LOG_MSG("Database \'" + event->database + "\' dropped.", mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
}
|
||||
|
||||
void MongoServer::handle(ReplicaSetRefreshed *event)
|
||||
{
|
||||
handleReplicaSetRefreshEvents(event->isError(), event->error(), event->replicaSet, false);
|
||||
}
|
||||
|
||||
void MongoServer::handleReplicaSetRefreshEvents(bool isError, EventError eventError,
|
||||
ReplicaSet const& replicaSet, bool expanded)
|
||||
{
|
||||
if (isError) { // Primary is unreachable
|
||||
_replicaSetInfo.reset(new ReplicaSet(replicaSet));
|
||||
LOG_MSG("Replica set folder refreshed with error. " + eventError.errorMessage() +
|
||||
". Connection: " + _connSettings->connectionName(), mongo::logger::LogSeverity::Error());
|
||||
_bus->publish(new ReplicaSetFolderRefreshed(this, eventError, true));
|
||||
return;
|
||||
}
|
||||
|
||||
// Primary is reachable
|
||||
// Update replica set settings and mongo server _replicaSetInfo
|
||||
_replicaSetInfo.reset(new ReplicaSet(replicaSet));
|
||||
_connSettings->setServerHost(_replicaSetInfo->primary.host());
|
||||
_connSettings->setServerPort(_replicaSetInfo->primary.port());
|
||||
_connSettings->replicaSetSettings()->setCachedSetName(
|
||||
_connSettings->replicaSetSettings()->setNameUserEntered().empty() ? _replicaSetInfo->setName : "");
|
||||
|
||||
LOG_MSG("Replica set folder refreshed. Connection: " + _connSettings->connectionName(),
|
||||
mongo::logger::LogSeverity::Info());
|
||||
_bus->publish(new ReplicaSetFolderRefreshed(this, expanded));
|
||||
}
|
||||
|
||||
void MongoServer::updateReplicaSetSettings(EstablishConnectionResponse* event)
|
||||
{
|
||||
if (!_connSettings->isReplicaSet())
|
||||
return;
|
||||
|
||||
_replicaSetInfo.reset(new ReplicaSet(event->replicaSet));
|
||||
_connSettings->setServerHost(_replicaSetInfo->primary.host());
|
||||
_connSettings->setServerPort(_replicaSetInfo->primary.port());
|
||||
_connSettings->replicaSetSettings()->setCachedSetName(
|
||||
_connSettings->replicaSetSettings()->setNameUserEntered().empty() ? _replicaSetInfo->setName : "");
|
||||
|
||||
if (_connSettings->replicaSetSettings()->setNameUserEntered().empty()) {
|
||||
// Cache replica set name for 2 times faster first connection
|
||||
if (ConnectionPrimary == _connectionType) {
|
||||
ConnectionSettings* originalConnSettings = AppRegistry::instance().settingsManager()
|
||||
->getConnectionSettingsByUuid(event->info._uuid);
|
||||
if (originalConnSettings) {
|
||||
auto setName = event->isError() ? "" : _replicaSetInfo->setName;
|
||||
originalConnSettings->replicaSetSettings()->setCachedSetName(setName);
|
||||
AppRegistry::instance().settingsManager()->save();
|
||||
LOG_MSG("Replica set name cached as \"" + setName + "\".", mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
else
|
||||
LOG_MSG("Failed to cache the replica set name.", mongo::logger::LogSeverity::Warning());
|
||||
}
|
||||
}
|
||||
else { // User entered set name is not empty, clear cached set name just in case
|
||||
ConnectionSettings* originalConnSettings = AppRegistry::instance().settingsManager()
|
||||
->getConnectionSettingsByUuid(event->info._uuid);
|
||||
if (originalConnSettings) {
|
||||
originalConnSettings->replicaSetSettings()->setCachedSetName("");
|
||||
AppRegistry::instance().settingsManager()->save();
|
||||
LOG_MSG("Replica set's cached set name cleared. Using user entered set name.",
|
||||
mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MongoServer::handleConnectionFailure(EstablishConnectionResponse* event)
|
||||
{
|
||||
_isConnected = false;
|
||||
|
||||
std::stringstream ss("Unknown error");
|
||||
auto eventErrorReason = event->errorReason;
|
||||
|
||||
if (_connSettings->isReplicaSet())
|
||||
{
|
||||
ss.clear();
|
||||
std::string server = "";
|
||||
if (_connSettings->replicaSetSettings()->members().size() > 0)
|
||||
server = "[" + _connSettings->replicaSetSettings()->members().front() + "]";
|
||||
|
||||
if (event->error().errorCode() == EventError::ErrorCode::ServerHasDifferentMembers) {
|
||||
ss << "Cannot connect to replica set \"" << _connSettings->connectionName() << "\"" << server
|
||||
<< ". \n\nA primary with different host name [" << event->replicaSet.primary <<
|
||||
"] found in server side. "
|
||||
"Please double check if same host names and ports are used as in server's replica set"
|
||||
" configuration. \nIf same set name is used for different replica sets, this configuration"
|
||||
" is supported only on different instances of Robomongo. "
|
||||
" Please open a new Robomongo instance for each replica set which has the same set name."
|
||||
"\n\nReason:\n" << event->error().errorMessage();
|
||||
}
|
||||
else {
|
||||
ss << "Cannot connect to replica set \"" << _connSettings->connectionName() << "\"" << server
|
||||
<< ". \nSet's primary is unreachable.\n\nReason:\n" << event->error().errorMessage();
|
||||
}
|
||||
|
||||
_bus->publish(new ConnectionFailedEvent(this, _handle, event->connectionType, ss.str(),
|
||||
ConnectionFailedEvent::MongoConnection));
|
||||
_app->fireConnectionFailedEvent(_handle, event->connectionType, ss.str(),
|
||||
ConnectionFailedEvent::MongoConnection);
|
||||
LOG_MSG("Establish connection failed. " + event->error().errorMessage() + ". Connection: "
|
||||
+ _connSettings->connectionName(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
else // single server
|
||||
{
|
||||
std::stringstream ss("Unknown error");
|
||||
auto eventErrorReason = event->errorReason;
|
||||
if (EstablishConnectionResponse::ErrorReason::MongoSslConnection == eventErrorReason)
|
||||
{
|
||||
auto reason = ConnectionFailedEvent::SslConnection;
|
||||
@@ -459,14 +147,85 @@ namespace Robomongo {
|
||||
|
||||
// When connection cannot be established, we should cleanup this instance of MongoServer if it wasn't
|
||||
// shown in UI (i.e. it is not a Secondary connection that is used for shells tab)
|
||||
if (_connectionType == ConnectionPrimary || _connectionType == ConnectionTest)
|
||||
if (_connectionType == ConnectionPrimary || _connectionType == ConnectionTest)
|
||||
{
|
||||
LOG_MSG("Establish connection failed. " + event->error().errorMessage() +
|
||||
". Connection: " + _connSettings->connectionName(),
|
||||
mongo::logger::LogSeverity::Error());
|
||||
_app->closeServer(this);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Save various information after successful connection
|
||||
const ConnectionInfo &info = event->info();
|
||||
_version = info._version;
|
||||
_storageEngineType = info._storageEngineType;
|
||||
_isConnected = true;
|
||||
// Save Replica Set Status
|
||||
_repPrimary = event->getRepPrimary(); // todo: what happens to this member if not replica set?
|
||||
_repMembersHealths = event->getRepMembersHealths();
|
||||
if (_settings->isReplicaSet()) {
|
||||
_settings->setServerHost(_repPrimary.host());
|
||||
_settings->setServerPort(_repPrimary.port());
|
||||
}
|
||||
|
||||
_bus->publish(new ConnectionEstablishedEvent(this, _connectionType));
|
||||
|
||||
// Do nothing if this is not a "primary" connection
|
||||
if (_connectionType != ConnectionPrimary)
|
||||
return;
|
||||
|
||||
clearDatabases();
|
||||
for (std::vector<std::string>::const_iterator it = info._databases.begin(); it != info._databases.end(); ++it) {
|
||||
const std::string &name = *it;
|
||||
MongoDatabase *db = new MongoDatabase(this, name);
|
||||
addDatabase(db);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Robomongo
|
||||
void MongoServer::handle(LoadDatabaseNamesResponse *event) {
|
||||
if (event->isError()) {
|
||||
_bus->publish(new DatabaseListLoadedEvent(this, event->error()));
|
||||
return;
|
||||
}
|
||||
|
||||
clearDatabases();
|
||||
for (std::vector<std::string>::iterator it = event->databaseNames.begin(); it != event->databaseNames.end(); ++it) {
|
||||
const std::string &name = *it;
|
||||
MongoDatabase *db = new MongoDatabase(this, name);
|
||||
addDatabase(db);
|
||||
}
|
||||
|
||||
_bus->publish(new DatabaseListLoadedEvent(this, _databases));
|
||||
}
|
||||
|
||||
void MongoServer::handle(InsertDocumentResponse *event) {
|
||||
_bus->publish(new InsertDocumentResponse(event->sender(), event->error()));
|
||||
}
|
||||
|
||||
void MongoServer::handle(RemoveDocumentResponse *event) {
|
||||
_bus->publish(new RemoveDocumentResponse(event->sender(), event->error()));
|
||||
}
|
||||
|
||||
void MongoServer::runWorkerThread() {
|
||||
_client = new MongoWorker(_settings->clone(),
|
||||
AppRegistry::instance().settingsManager()->loadMongoRcJs(),
|
||||
AppRegistry::instance().settingsManager()->batchSize(),
|
||||
AppRegistry::instance().settingsManager()->mongoTimeoutSec(),
|
||||
AppRegistry::instance().settingsManager()->shellTimeoutSec());
|
||||
}
|
||||
|
||||
void MongoServer::handle(CreateDatabaseResponse *event) {
|
||||
genericResponseHandler(event, "Failed to create database.");
|
||||
}
|
||||
|
||||
void MongoServer::handle(DropDatabaseResponse *event) {
|
||||
genericResponseHandler(event, "Failed to drop database.");
|
||||
}
|
||||
|
||||
void MongoServer::genericResponseHandler(Event *event, const std::string &userFriendlyMessage) {
|
||||
if (!event->isError())
|
||||
return;
|
||||
|
||||
_bus->publish(new OperationFailedEvent(this, event->error().errorMessage(), userFriendlyMessage));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,11 @@ namespace Robomongo
|
||||
class App;
|
||||
|
||||
// Messages
|
||||
struct EstablishConnectionResponse;
|
||||
struct RefreshReplicaSetFolderResponse;
|
||||
class EstablishConnectionResponse;
|
||||
class LoadDatabaseNamesResponse;
|
||||
class InsertDocumentResponse;
|
||||
struct CreateDatabaseResponse;
|
||||
struct DropDatabaseResponse;
|
||||
class CreateDatabaseResponse;
|
||||
class DropDatabaseResponse;
|
||||
|
||||
/**
|
||||
* @brief MongoServer represents active connection to MongoDB server.
|
||||
@@ -41,52 +40,22 @@ namespace Robomongo
|
||||
void runWorkerThread();
|
||||
|
||||
/**
|
||||
* @brief Try to connect to MongoDB single server or replica set.
|
||||
* @brief Try to connect to MongoDB server.
|
||||
* @throws MongoException, if fails
|
||||
*/
|
||||
void tryConnect();
|
||||
bool isConnected()const;
|
||||
|
||||
/**
|
||||
* @brief Try to re-connect to MongoDB server in order to refresh connection view.
|
||||
* Never shown in Explorer and can be used to refresh (via reconnecting) current connection view.
|
||||
* (i.e. db version, storage engine etc...)
|
||||
* @throws MongoException, if fails
|
||||
*/
|
||||
void tryRefresh();
|
||||
|
||||
/**
|
||||
* @brief Try to re-connect to MongoDB replica set in order to refresh connection view.
|
||||
* It is used to refresh (via reconnecting) current connection view.
|
||||
* (i.e. db version, storage engine, current replica set primary, status of replica set etc...)
|
||||
* It will update Explorer widgets depending on replica set status (online if primary reachable and
|
||||
* offline otherwise)
|
||||
*/
|
||||
void tryRefreshReplicaSetConnection();
|
||||
|
||||
/**
|
||||
* @brief Try to re-connect to MongoDB replica set in order to refresh connection view.
|
||||
* It is used to refresh (via reconnecting) current connection view.
|
||||
* (i.e. db version, storage engine, current replica set primary, status of replica set etc...)
|
||||
* It will update only 'Replica Set' folder widgets depending on replica set status
|
||||
* (online if primary reachable and offline otherwise)
|
||||
*/
|
||||
void tryRefreshReplicaSetFolder(bool expanded, bool showLoading = true);
|
||||
|
||||
bool isConnected() const;
|
||||
|
||||
void addDatabase(MongoDatabase *database);
|
||||
void createDatabase(const std::string &dbName);
|
||||
void dropDatabase(const std::string &dbName);
|
||||
QStringList getDatabasesNames() const;
|
||||
QList<MongoDatabase*> const& databases() const { return _databases; };
|
||||
MongoDatabase *findDatabaseByName(const std::string &dbName) const;
|
||||
|
||||
void insertDocuments(const std::vector<mongo::BSONObj> &objCont, const MongoNamespace &ns);
|
||||
void insertDocument(const mongo::BSONObj &obj, const MongoNamespace &ns);
|
||||
void saveDocuments(const std::vector<mongo::BSONObj> &objCont, const MongoNamespace &ns);
|
||||
void saveDocument(const mongo::BSONObj &obj, const MongoNamespace &ns);
|
||||
void removeDocuments(mongo::Query query, const MongoNamespace &ns, RemoveDocumentCount removeCount,
|
||||
int index = 0);
|
||||
void removeDocuments(mongo::Query query, const MongoNamespace &ns, bool justOne = true);
|
||||
float version() const{ return _version; }
|
||||
const std::string& getStorageEngineType() const { return _storageEngineType; }
|
||||
|
||||
@@ -99,30 +68,27 @@ namespace Robomongo
|
||||
* @brief Loads databases of this server asynchronously.
|
||||
*/
|
||||
void loadDatabases();
|
||||
MongoWorker *const worker() const { return _worker; }
|
||||
MongoWorker *const client() const { return _client; }
|
||||
|
||||
ReplicaSet* replicaSetInfo() const { return _replicaSetInfo.get(); }
|
||||
|
||||
void handle(ReplicaSetRefreshed *event);
|
||||
// --- Getters ---
|
||||
const mongo::HostAndPort& getRepPrimary() const { return _repPrimary; }
|
||||
const std::vector<bool>& getRepMembersHealths() const { return _repMembersHealths; }
|
||||
|
||||
protected Q_SLOTS:
|
||||
void handle(EstablishConnectionResponse *event);
|
||||
void handle(RefreshReplicaSetFolderResponse *event);
|
||||
void handle(LoadDatabaseNamesResponse *event);
|
||||
void handle(InsertDocumentResponse *event);
|
||||
void handle(RemoveDocumentResponse *event);
|
||||
void handle(CreateDatabaseResponse *event);
|
||||
void handle(DropDatabaseResponse *event);
|
||||
|
||||
private:
|
||||
private:
|
||||
void clearDatabases();
|
||||
void handleReplicaSetRefreshEvents(bool isError, EventError eventError, ReplicaSet const& replicaSet,
|
||||
bool expanded);
|
||||
void updateReplicaSetSettings(EstablishConnectionResponse* event);
|
||||
void handleConnectionFailure(EstablishConnectionResponse* event);
|
||||
void addDatabase(MongoDatabase *database);
|
||||
void genericResponseHandler(Event *event, const std::string &userFriendlyMessage);
|
||||
|
||||
MongoWorker *_worker;
|
||||
std::unique_ptr<ConnectionSettings> _connSettings;
|
||||
MongoWorker *_client;
|
||||
ConnectionSettings *_settings;
|
||||
EventBus *_bus;
|
||||
App *_app;
|
||||
|
||||
@@ -133,7 +99,10 @@ namespace Robomongo
|
||||
int _handle;
|
||||
|
||||
QList<MongoDatabase *> _databases;
|
||||
std::unique_ptr<ReplicaSet> _replicaSetInfo;
|
||||
|
||||
// Replica Set Status
|
||||
mongo::HostAndPort _repPrimary;
|
||||
std::vector<bool> _repMembersHealths; // todo: vector of pairs of host and health
|
||||
};
|
||||
|
||||
class MongoServerLoadingDatabasesEvent : public Event
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "robomongo/core/settings/SettingsManager.h"
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
{
|
||||
|
||||
MongoShell::MongoShell(MongoServer *server, const ScriptInfo &scriptInfo) :
|
||||
QObject(),
|
||||
@@ -24,7 +24,7 @@ namespace Robomongo
|
||||
{
|
||||
AppRegistry::instance().bus()->publish(new ScriptExecutingEvent(this));
|
||||
_scriptInfo.setScript(QtUtils::toQString(script));
|
||||
AppRegistry::instance().bus()->send(_server->worker(), new ExecuteScriptRequest(this, query(), dbName));
|
||||
AppRegistry::instance().bus()->send(_server->client(), new ExecuteScriptRequest(this, query(), dbName));
|
||||
LOG_MSG(_scriptInfo.script(), mongo::logger::LogSeverity::Info());
|
||||
}
|
||||
|
||||
@@ -37,19 +37,19 @@ namespace Robomongo
|
||||
{
|
||||
if (_scriptInfo.execute()) {
|
||||
AppRegistry::instance().bus()->publish(new ScriptExecutingEvent(this));
|
||||
AppRegistry::instance().bus()->send(_server->worker(), new ExecuteScriptRequest(this, query(), dbName));
|
||||
AppRegistry::instance().bus()->send(_server->client(), new ExecuteScriptRequest(this, query(), dbName));
|
||||
if (!_scriptInfo.script().isEmpty())
|
||||
LOG_MSG(_scriptInfo.script(), mongo::logger::LogSeverity::Info());
|
||||
} else {
|
||||
AppRegistry::instance().bus()->publish(new ScriptExecutingEvent(this));
|
||||
_scriptInfo.setScript("");
|
||||
AppRegistry::instance().bus()->send(_server->worker(), new ExecuteScriptRequest(this, query() , dbName));
|
||||
AppRegistry::instance().bus()->send(_server->client(), new ExecuteScriptRequest(this, query() , dbName));
|
||||
}
|
||||
}
|
||||
|
||||
void MongoShell::query(int resultIndex, const MongoQueryInfo &info)
|
||||
{
|
||||
AppRegistry::instance().bus()->send(_server->worker(), new ExecuteQueryRequest(this, resultIndex, info));
|
||||
AppRegistry::instance().bus()->send(_server->client(), new ExecuteQueryRequest(this, resultIndex, info));
|
||||
}
|
||||
|
||||
void MongoShell::autocomplete(const std::string &prefix)
|
||||
@@ -57,12 +57,12 @@ namespace Robomongo
|
||||
AutocompletionMode autocompletionMode = AppRegistry::instance().settingsManager()->autocompletionMode();
|
||||
if (autocompletionMode == AutocompleteNone)
|
||||
return;
|
||||
AppRegistry::instance().bus()->send(_server->worker(), new AutocompleteRequest(this, prefix, autocompletionMode));
|
||||
AppRegistry::instance().bus()->send(_server->client(), new AutocompleteRequest(this, prefix, autocompletionMode));
|
||||
}
|
||||
|
||||
void MongoShell::stop()
|
||||
{
|
||||
// _server->worker()->interrupt();
|
||||
// _server->client()->interrupt();
|
||||
// mongo::Scope::setInterruptFlag(true);
|
||||
}
|
||||
|
||||
@@ -94,17 +94,8 @@ namespace Robomongo
|
||||
void MongoShell::handle(ExecuteScriptResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
if (_server->connectionRecord()->isReplicaSet()) {
|
||||
AppRegistry::instance().bus()->publish(
|
||||
new ReplicaSetRefreshed(this, event->error(), event->error().replicaSetInfo()));
|
||||
|
||||
AppRegistry::instance().bus()->publish(new ScriptExecutedEvent(this, event->error()));
|
||||
return;
|
||||
}
|
||||
else { // single server
|
||||
AppRegistry::instance().bus()->publish(new ScriptExecutedEvent(this, event->error()));
|
||||
return;
|
||||
}
|
||||
AppRegistry::instance().bus()->publish(new ScriptExecutedEvent(this, event->error()));
|
||||
return;
|
||||
}
|
||||
|
||||
AppRegistry::instance().bus()->publish(new ScriptExecutedEvent(this, event->result, event->empty));
|
||||
|
||||
@@ -29,22 +29,15 @@ namespace Robomongo
|
||||
{
|
||||
public:
|
||||
MongoShellExecResult() { }
|
||||
|
||||
MongoShellExecResult(const std::vector<MongoShellResult> &results,
|
||||
const std::string ¤tServer, bool isCurrentServerValid,
|
||||
const std::string ¤tDatabase, bool isCurrentDatabaseValid);
|
||||
|
||||
MongoShellExecResult(bool error, std::string const& errorMsg = "") :
|
||||
_error(error), _errorMessage(errorMsg) { }
|
||||
|
||||
std::vector<MongoShellResult> results() const { return _results; }
|
||||
std::string currentServer() const { return _currentServer; }
|
||||
void setCurrentServer(std::string const& server) { _currentServer = server; }
|
||||
std::string currentDatabase() const { return _currentDatabase; }
|
||||
std::string currentDatabase() const { return _currentDatabase; }
|
||||
bool isCurrentServerValid() const { return _isCurrentServerValid; }
|
||||
bool isCurrentDatabaseValid() const { return _isCurrentDatabaseValid; }
|
||||
std::string errorMessage() const { return _errorMessage; }
|
||||
bool error() const { return _error; }
|
||||
|
||||
private:
|
||||
std::vector<MongoShellResult> _results;
|
||||
@@ -52,7 +45,5 @@ namespace Robomongo
|
||||
std::string _currentDatabase;
|
||||
bool _isCurrentServerValid;
|
||||
bool _isCurrentDatabaseValid;
|
||||
std::string _errorMessage;
|
||||
bool _error = false;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -25,10 +25,10 @@ namespace Robomongo
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
bool isSimpleType(Robomongo::BsonTreeItem const *item)
|
||||
bool isSimpleType(Robomongo::BsonTreeItem *item)
|
||||
{
|
||||
return BsonUtils::isSimpleType(item->type()) ||
|
||||
BsonUtils::isUuidType(item->type(), item->binType());
|
||||
return Robomongo::BsonUtils::isSimpleType(item->type())
|
||||
|| Robomongo::BsonUtils::isUuidType(item->type(), item->binType());
|
||||
}
|
||||
|
||||
bool isObjectIdType(Robomongo::BsonTreeItem *item)
|
||||
@@ -41,17 +41,17 @@ namespace Robomongo
|
||||
return indexes.count() > 1;
|
||||
}
|
||||
|
||||
bool isDocumentType(BsonTreeItem const *item)
|
||||
bool isDocumentType(BsonTreeItem *item)
|
||||
{
|
||||
return BsonUtils::isDocument(item->type());
|
||||
return Robomongo::BsonUtils::isDocument(item->type());
|
||||
}
|
||||
|
||||
bool isArrayChild(BsonTreeItem const *item)
|
||||
bool isArrayChild(BsonTreeItem *item)
|
||||
{
|
||||
return BsonUtils::isArray(dynamic_cast<BsonTreeItem*>(item->parent())->type());
|
||||
return Robomongo::BsonUtils::isArray(dynamic_cast<BsonTreeItem *>(item->parent())->type());
|
||||
}
|
||||
|
||||
bool isDocumentRoot(BsonTreeItem const *item)
|
||||
bool isDocumentRoot(BsonTreeItem *item)
|
||||
{
|
||||
return ( item == item->superParent() );
|
||||
}
|
||||
@@ -102,8 +102,8 @@ namespace Robomongo
|
||||
_queryInfo(queryInfo)
|
||||
{
|
||||
QWidget *wid = dynamic_cast<QWidget*>(_observer);
|
||||
AppRegistry::instance().bus()->subscribe(this, InsertDocumentResponse::Type, _shell->server());
|
||||
AppRegistry::instance().bus()->subscribe(this, RemoveDocumentResponse::Type, _shell->server());
|
||||
AppRegistry::instance().bus()->subscribe(this, InsertDocumentResponse::Type);
|
||||
AppRegistry::instance().bus()->subscribe(this, RemoveDocumentResponse::Type);
|
||||
|
||||
_deleteDocumentAction = new QAction("Delete Document...", wid);
|
||||
VERIFY(connect(_deleteDocumentAction, SIGNAL(triggered()), SLOT(onDeleteDocument())));
|
||||
@@ -158,18 +158,19 @@ namespace Robomongo
|
||||
if (onItem && isEditable) menu->addAction(_editDocumentAction);
|
||||
if (onItem) menu->addAction(_viewDocumentAction);
|
||||
if (isEditable) menu->addAction(_insertDocumentAction);
|
||||
if (onItem && (isSimple || isDocument)) menu->addSeparator();
|
||||
if (onItem && isSimple) menu->addAction(_copyValueAction);
|
||||
|
||||
if (onItem && (isSimple || isDocument)) menu->addSeparator();
|
||||
|
||||
if (onItem && isSimple) menu->addAction(_copyValueAction);
|
||||
if (onItem && (isSimple || isDocument) && isNotArrayChild && !isRoot)
|
||||
menu->addAction(_copyValueNameAction);
|
||||
|
||||
if (onItem && (isSimple || isDocument) && !isRoot)
|
||||
menu->addAction(_copyValuePathAction);
|
||||
|
||||
if (onItem && isObjectId) menu->addAction(_copyTimestampAction);
|
||||
if (onItem && isDocument) menu->addAction(_copyJsonAction);
|
||||
|
||||
if (onItem && isEditable) menu->addSeparator();
|
||||
|
||||
if (onItem && isEditable) menu->addAction(_deleteDocumentAction);
|
||||
}
|
||||
|
||||
@@ -181,12 +182,11 @@ namespace Robomongo
|
||||
if (isEditable) menu->addAction(_deleteDocumentsAction);
|
||||
}
|
||||
|
||||
void Notifier::deleteDocuments(std::vector<BsonTreeItem*> const& items, bool force)
|
||||
void Notifier::deleteDocuments(std::vector<BsonTreeItem*> items, bool force)
|
||||
{
|
||||
bool isNeededRefresh = false;
|
||||
|
||||
int index = 0;
|
||||
for (auto const * const documentItem : items) {
|
||||
for (std::vector<BsonTreeItem*>::const_iterator it = items.begin(); it != items.end(); ++it) {
|
||||
BsonTreeItem * documentItem = *it;
|
||||
if (!documentItem)
|
||||
break;
|
||||
|
||||
@@ -194,8 +194,7 @@ namespace Robomongo
|
||||
mongo::BSONElement id = obj.getField("_id");
|
||||
|
||||
if (id.eoo()) {
|
||||
QMessageBox::warning(dynamic_cast<QWidget*>(_observer), "Cannot delete",
|
||||
"Selected document doesn't have _id field. \n"
|
||||
QMessageBox::warning(dynamic_cast<QWidget*>(_observer), "Cannot delete", "Selected document doesn't have _id field. \n"
|
||||
"Maybe this is a system document that should be managed in a special way?");
|
||||
break;
|
||||
}
|
||||
@@ -215,97 +214,44 @@ namespace Robomongo
|
||||
}
|
||||
|
||||
isNeededRefresh = true;
|
||||
|
||||
RemoveDocumentCount removeCount = items.size() == 1 ? RemoveDocumentCount::ONE :
|
||||
RemoveDocumentCount::MULTI;
|
||||
_shell->server()->removeDocuments(query, _queryInfo._info._ns, removeCount, index);
|
||||
++index;
|
||||
_shell->server()->removeDocuments(query, _queryInfo._info._ns);
|
||||
}
|
||||
|
||||
if (isNeededRefresh)
|
||||
_shell->query(0, _queryInfo);
|
||||
}
|
||||
|
||||
void Notifier::handle(InsertDocumentResponse *event)
|
||||
{
|
||||
if (event->isError()) { // Error
|
||||
if (_shell->server()->connectionRecord()->isReplicaSet()) {
|
||||
// Insert document from tab results window (Notifier, OutputWindow widget)
|
||||
if (EventError::SetPrimaryUnreachable == event->error().errorCode()) {
|
||||
AppRegistry::instance().bus()->publish(
|
||||
new ReplicaSetRefreshed(_shell, event->error(), event->error().replicaSetInfo()));
|
||||
}
|
||||
}
|
||||
else // single server
|
||||
QMessageBox::warning(NULL, "Database Error", QString::fromStdString(event->error().errorMessage()));
|
||||
|
||||
if (event->isError()) {
|
||||
QMessageBox::warning(NULL, "Database Error", QString::fromStdString(event->error().errorMessage()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Success
|
||||
_shell->query(0, _queryInfo);
|
||||
}
|
||||
|
||||
void Notifier::handle(RemoveDocumentResponse *event)
|
||||
{
|
||||
if (event->isError()) {
|
||||
if (!(event->removeCount == RemoveDocumentCount::MULTI && event->index > 0))
|
||||
QMessageBox::warning(NULL, "Database Error", QString::fromStdString(event->error().errorMessage()));
|
||||
}
|
||||
else // Success
|
||||
_shell->query(0, _queryInfo);
|
||||
}
|
||||
if (event->isError()) {
|
||||
// Commented because when you'll delete multiple documents,
|
||||
// we'll receive this event as many times as many selected
|
||||
// documents you have. This is incorrect and remove of
|
||||
// multiple documents should be a single command, instead
|
||||
// of many. Error message should be printed in the logs.
|
||||
|
||||
void Notifier::onCopyNameDocument()
|
||||
{
|
||||
QModelIndex const& selectedInd = _observer->selectedIndex();
|
||||
if (!selectedInd.isValid())
|
||||
// QMessageBox::warning(NULL, "Database Error", QString::fromStdString(event->error().errorMessage()));
|
||||
return;
|
||||
|
||||
BsonTreeItem const *documentItem = QtUtils::item<BsonTreeItem*>(selectedInd);
|
||||
if (!documentItem)
|
||||
return;
|
||||
|
||||
if (!(detail::isSimpleType(documentItem) || detail::isDocumentType(documentItem) ||
|
||||
!detail::isArrayChild(documentItem) || !detail::isDocumentRoot(documentItem)))
|
||||
return;
|
||||
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setText(QString::fromStdString(documentItem->fieldName()));
|
||||
}
|
||||
|
||||
void Notifier::onCopyPathDocument()
|
||||
{
|
||||
QModelIndex const& selectedInd = _observer->selectedIndex();
|
||||
if (!selectedInd.isValid())
|
||||
return;
|
||||
|
||||
BsonTreeItem const *documentItem = QtUtils::item<BsonTreeItem*>(selectedInd);
|
||||
if (!documentItem)
|
||||
return;
|
||||
|
||||
if (!(detail::isSimpleType(documentItem) || detail::isDocumentType(documentItem) ||
|
||||
!detail::isDocumentRoot(documentItem)))
|
||||
return;
|
||||
|
||||
QStringList namesList;
|
||||
BsonTreeItem const *documentItemHelper = documentItem;
|
||||
|
||||
while (!detail::isDocumentRoot(documentItemHelper)) {
|
||||
if (!detail::isArrayChild(documentItemHelper)) {
|
||||
namesList.push_front(QString::fromStdString(documentItemHelper->fieldName()));
|
||||
}
|
||||
|
||||
documentItemHelper = dynamic_cast<BsonTreeItem*>(documentItemHelper->parent());
|
||||
}
|
||||
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setText(namesList.join("."));
|
||||
}
|
||||
|
||||
void Notifier::handleDeleteCommand()
|
||||
{
|
||||
if (_observer->selectedIndexes().count() > 1)
|
||||
if (_observer->selectedIndexes().count() > 1) {
|
||||
onDeleteDocuments();
|
||||
else
|
||||
onDeleteDocument();
|
||||
} else {
|
||||
onDeleteDocument();
|
||||
}
|
||||
}
|
||||
|
||||
void Notifier::onDeleteDocuments()
|
||||
@@ -317,15 +263,13 @@ namespace Robomongo
|
||||
if (!detail::isMultiSelection(selectedIndexes))
|
||||
return;
|
||||
|
||||
int const answer = QMessageBox::question(dynamic_cast<QWidget*>(_observer), "Delete",
|
||||
QString("Do you want to delete %1 selected documents?").
|
||||
arg(selectedIndexes.count()));
|
||||
|
||||
if (QMessageBox::Yes == answer) {
|
||||
int answer = QMessageBox::question(dynamic_cast<QWidget*>(_observer), "Delete", QString("Do you want to delete %1 selected documents?").arg(selectedIndexes.count()));
|
||||
if (answer == QMessageBox::Yes) {
|
||||
std::vector<BsonTreeItem*> items;
|
||||
for (auto index : selectedIndexes)
|
||||
items.push_back(QtUtils::item<BsonTreeItem*>(index));
|
||||
|
||||
for (QModelIndexList::const_iterator it = selectedIndexes.begin(); it != selectedIndexes.end(); ++it) {
|
||||
BsonTreeItem *item = QtUtils::item<BsonTreeItem*>(*it);
|
||||
items.push_back(item);
|
||||
}
|
||||
deleteDocuments(items, true);
|
||||
}
|
||||
}
|
||||
@@ -399,7 +343,7 @@ namespace Robomongo
|
||||
json, true, dynamic_cast<QWidget*>(_observer));
|
||||
|
||||
editor->setWindowTitle("View Document");
|
||||
editor->exec();
|
||||
editor->show();
|
||||
}
|
||||
|
||||
void Notifier::onInsertDocument()
|
||||
@@ -421,6 +365,8 @@ namespace Robomongo
|
||||
for (DocumentTextEditor::ReturnType::const_iterator it = obj.begin(); it != obj.end(); ++it) {
|
||||
_shell->server()->insertDocument(*it, _queryInfo._info._ns);
|
||||
}
|
||||
|
||||
_shell->query(0, _queryInfo);
|
||||
}
|
||||
|
||||
void Notifier::onCopyDocument()
|
||||
@@ -440,6 +386,53 @@ namespace Robomongo
|
||||
clipboard->setText(documentItem->value());
|
||||
}
|
||||
|
||||
void Notifier::onCopyNameDocument()
|
||||
{
|
||||
QModelIndex selectedInd = _observer->selectedIndex();
|
||||
if (!selectedInd.isValid())
|
||||
return;
|
||||
|
||||
BsonTreeItem *documentItem = QtUtils::item<BsonTreeItem*>(selectedInd);
|
||||
if (!documentItem)
|
||||
return;
|
||||
|
||||
if ( !(detail::isSimpleType(documentItem) || detail::isDocumentType(documentItem) ||
|
||||
!detail::isArrayChild(documentItem) || !detail::isDocumentRoot(documentItem)) )
|
||||
return;
|
||||
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setText(QString::fromStdString(documentItem->fieldName()));
|
||||
}
|
||||
|
||||
void Notifier::onCopyPathDocument()
|
||||
{
|
||||
QModelIndex selectedInd = _observer->selectedIndex();
|
||||
if (!selectedInd.isValid())
|
||||
return;
|
||||
|
||||
BsonTreeItem *documentItem = QtUtils::item<BsonTreeItem*>(selectedInd);
|
||||
if (!documentItem)
|
||||
return;
|
||||
|
||||
if ( !(detail::isSimpleType(documentItem) || detail::isDocumentType(documentItem) ||
|
||||
!detail::isDocumentRoot(documentItem)) )
|
||||
return;
|
||||
|
||||
QStringList namesList;
|
||||
BsonTreeItem *documentItemHelper = documentItem;
|
||||
|
||||
while ( !detail::isDocumentRoot(documentItemHelper) ) {
|
||||
if ( !detail::isArrayChild(documentItemHelper) ) {
|
||||
namesList.push_front( QString::fromStdString(documentItemHelper->fieldName()) );
|
||||
}
|
||||
|
||||
documentItemHelper = dynamic_cast<BsonTreeItem *>(documentItemHelper->parent());
|
||||
}
|
||||
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setText(namesList.join("."));
|
||||
}
|
||||
|
||||
void Notifier::onCopyTimestamp()
|
||||
{
|
||||
QModelIndex selectedInd = _observer->selectedIndex();
|
||||
|
||||
@@ -14,14 +14,14 @@ namespace Robomongo
|
||||
class MongoShell;
|
||||
class BsonTreeItem;
|
||||
class InsertDocumentResponse;
|
||||
struct RemoveDocumentResponse;
|
||||
class RemoveDocumentResponse;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
bool isSimpleType(BsonTreeItem const *item);
|
||||
bool isSimpleType(BsonTreeItem *item);
|
||||
bool isObjectIdType(BsonTreeItem *item);
|
||||
bool isMultiSelection(const QModelIndexList &indexes);
|
||||
bool isDocumentType(BsonTreeItem const *item);
|
||||
bool isDocumentType(BsonTreeItem *item);
|
||||
QModelIndexList uniqueRows(QModelIndexList indexes, bool returnSuperParents = false);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Robomongo
|
||||
void initMenu(QMenu *const menu, BsonTreeItem *const item);
|
||||
void initMultiSelectionMenu(QMenu *const menu);
|
||||
|
||||
void deleteDocuments(std::vector<BsonTreeItem*> const& items, bool force);
|
||||
void deleteDocuments(std::vector<BsonTreeItem*> items, bool force);
|
||||
void handleDeleteCommand();
|
||||
|
||||
public Q_SLOTS:
|
||||
@@ -55,15 +55,13 @@ namespace Robomongo
|
||||
void onViewDocument();
|
||||
void onInsertDocument();
|
||||
void onCopyDocument();
|
||||
void onCopyNameDocument();
|
||||
void onCopyPathDocument();
|
||||
void onCopyTimestamp();
|
||||
void onCopyJson();
|
||||
void handle(InsertDocumentResponse *event);
|
||||
void handle(RemoveDocumentResponse *event);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onCopyNameDocument();
|
||||
void onCopyPathDocument();
|
||||
|
||||
private:
|
||||
QAction *_deleteDocumentAction;
|
||||
QAction *_deleteDocumentsAction;
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Robomongo
|
||||
{
|
||||
ScriptEngine::ScriptEngine(ConnectionSettings *connection, int timeoutSec) :
|
||||
_connection(connection),
|
||||
_scope(nullptr),
|
||||
_scope(NULL),
|
||||
_engine(NULL),
|
||||
_timeoutSec(timeoutSec),
|
||||
_initialized(false),
|
||||
@@ -65,20 +65,26 @@ namespace Robomongo
|
||||
|
||||
ScriptEngine::~ScriptEngine()
|
||||
{
|
||||
QMutexLocker lock(&_mutex);
|
||||
|
||||
delete _scope;
|
||||
_scope = NULL;
|
||||
|
||||
// delete _engine;
|
||||
// _engine = NULL;
|
||||
}
|
||||
|
||||
void ScriptEngine::init(bool isLoadMongoRcJs, const std::string& serverAddr, const std::string& dbName)
|
||||
void ScriptEngine::init(bool isLoadMongoRcJs)
|
||||
{
|
||||
QMutexLocker lock(&_mutex);
|
||||
|
||||
std::string connectDatabase = dbName.empty() ? "test" : dbName;
|
||||
std::string connectDatabase = "test";
|
||||
|
||||
if (_connection->hasEnabledPrimaryCredential())
|
||||
connectDatabase = _connection->primaryCredential()->databaseName();
|
||||
|
||||
std::stringstream ss;
|
||||
auto hostAndPort = serverAddr.empty() ? _connection->hostAndPort().toString() : serverAddr;
|
||||
ss << "db = connect('" << hostAndPort << "/" << connectDatabase;
|
||||
ss << "db = connect('" << _connection->info().toString() << "/" << connectDatabase;
|
||||
|
||||
// v0.9
|
||||
// ss << "db = connect('" << _connection->serverHost() << ":" << _connection->serverPort() << _connection->sslInfo() << _connection->sshInfo() << "/" << connectDatabase;
|
||||
@@ -102,23 +108,23 @@ namespace Robomongo
|
||||
mongo::globalScriptEngine->setScopeInitCallback(mongo::shell_utils::initScope);
|
||||
mongo::globalScriptEngine->enableJIT(true);
|
||||
|
||||
_scope.reset(mongo::globalScriptEngine->newScope());
|
||||
mongo::Scope *scope = mongo::globalScriptEngine->newScope();
|
||||
_scope = scope;
|
||||
_engine = mongo::globalScriptEngine;
|
||||
|
||||
// Load '.mongorc.js' from user's home directory
|
||||
if (isLoadMongoRcJs) {
|
||||
QString mongorcPath = QString("%1/.mongorc.js").arg(QDir::homePath());
|
||||
if (QFile::exists(mongorcPath)) {
|
||||
_scope->execFile(QtUtils::toStdString(mongorcPath), false, false);
|
||||
scope->execFile(QtUtils::toStdString(mongorcPath), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Load '.robomongorc.js'
|
||||
QString robomongorcPath = QString("%1/.robomongorc.js").arg(QDir::homePath());
|
||||
if (QFile::exists(robomongorcPath)) {
|
||||
_scope->execFile(QtUtils::toStdString(robomongorcPath), false, false);
|
||||
scope->execFile(QtUtils::toStdString(robomongorcPath), false, false);
|
||||
}
|
||||
_failedScope = false;
|
||||
}
|
||||
|
||||
// Esprima ECMAScript parser: http://esprima.org/
|
||||
@@ -155,10 +161,8 @@ namespace Robomongo
|
||||
{
|
||||
QMutexLocker lock(&_mutex);
|
||||
|
||||
if (!_scope) {
|
||||
_failedScope = true;
|
||||
return MongoShellExecResult(true, "Connection error. Uninitialized mongo scope.");
|
||||
}
|
||||
if (!_scope)
|
||||
return MongoShellExecResult();
|
||||
|
||||
/*
|
||||
* Replace all commands ('show dbs', 'use db' etc.) with call
|
||||
@@ -198,15 +202,10 @@ namespace Robomongo
|
||||
|
||||
if (true /* ! wascmd */) {
|
||||
try {
|
||||
bool failed = false;
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
if ( _scope->exec( statement , "(shell)" , false , true , false, _timeoutSec * 1000) ) {
|
||||
_scope->exec( "__robomongoLastRes = __lastres__; shellPrintHelper( __lastres__ );",
|
||||
"(shell2)" , true , true , false, _timeoutSec * 1000);
|
||||
}
|
||||
else { // failed to run script
|
||||
failed = true;
|
||||
_scope->exec( "__robomongoLastRes = __lastres__; shellPrintHelper( __lastres__ );" , "(shell2)" , true , true , false, _timeoutSec * 1000);
|
||||
}
|
||||
|
||||
qint64 elapsed = timer.elapsed();
|
||||
@@ -214,10 +213,6 @@ namespace Robomongo
|
||||
std::string logs = __logs.str();
|
||||
std::string answer = logs.c_str();
|
||||
std::string type = __type.c_str();
|
||||
|
||||
if (failed)
|
||||
return MongoShellExecResult(true, answer);
|
||||
|
||||
std::vector<MongoDocumentPtr> docs = MongoDocument::fromBsonObj(__objects);
|
||||
|
||||
if (!answer.empty() || docs.size() > 0)
|
||||
@@ -270,9 +265,6 @@ namespace Robomongo
|
||||
|
||||
void ScriptEngine::ping()
|
||||
{
|
||||
if (!_scope)
|
||||
return;
|
||||
|
||||
QMutexLocker lock(&_mutex);
|
||||
_scope->exec("if (db) { db.runCommand({ping:1}); }", "(ping)", false, false, false, 3000);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Robomongo
|
||||
ScriptEngine(ConnectionSettings *connection, int timeoutSec);
|
||||
~ScriptEngine();
|
||||
|
||||
void init(bool isLoadMongoJs, const std::string& serverAddr = "", const std::string& dbName = "");
|
||||
void init(bool isLoadMongoJs);
|
||||
MongoShellExecResult exec(const std::string &script, const std::string &dbName = std::string());
|
||||
void interrupt();
|
||||
|
||||
@@ -29,8 +29,6 @@ namespace Robomongo
|
||||
|
||||
void invalidateDbCollectionsCache();
|
||||
|
||||
bool failedScope() const { return _failedScope; }
|
||||
|
||||
private:
|
||||
ConnectionSettings *_connection;
|
||||
|
||||
@@ -44,8 +42,7 @@ namespace Robomongo
|
||||
|
||||
int _timeoutSec;
|
||||
mongo::ScriptEngine *_engine;
|
||||
std::unique_ptr<mongo::Scope> _scope;
|
||||
bool _failedScope = false;
|
||||
mongo::Scope *_scope;
|
||||
QMutex _mutex;
|
||||
bool _initialized;
|
||||
};
|
||||
|
||||
@@ -5,11 +5,6 @@ namespace Robomongo
|
||||
{
|
||||
R_REGISTER_EVENT(EstablishConnectionRequest)
|
||||
R_REGISTER_EVENT(EstablishConnectionResponse)
|
||||
R_REGISTER_EVENT(ReplicaSetRefreshed)
|
||||
R_REGISTER_EVENT(RefreshReplicaSetFolderRequest)
|
||||
R_REGISTER_EVENT(RefreshReplicaSetFolderResponse)
|
||||
R_REGISTER_EVENT(ReplicaSetFolderLoading)
|
||||
R_REGISTER_EVENT(ReplicaSetFolderRefreshed)
|
||||
R_REGISTER_EVENT(LoadDatabaseNamesRequest)
|
||||
R_REGISTER_EVENT(LoadDatabaseNamesResponse)
|
||||
R_REGISTER_EVENT(LoadCollectionNamesRequest)
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "robomongo/core/events/MongoEventsInfo.h"
|
||||
#include "robomongo/core/Event.h"
|
||||
#include "robomongo/core/Enums.h"
|
||||
#include "robomongo/core/mongodb/ReplicaSet.h"
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
@@ -27,118 +26,54 @@ namespace Robomongo
|
||||
* @brief EstablishConnection
|
||||
*/
|
||||
|
||||
struct EstablishConnectionRequest : public Event
|
||||
class EstablishConnectionRequest : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
EstablishConnectionRequest(QObject *sender, ConnectionType connectionType, std::string const& uuid) :
|
||||
EstablishConnectionRequest(QObject *sender, ConnectionType connectionType) :
|
||||
Event(sender),
|
||||
connectionType(connectionType),
|
||||
uuid(uuid) {}
|
||||
connectionType(connectionType) {}
|
||||
|
||||
ConnectionType const connectionType;
|
||||
std::string const uuid;
|
||||
ConnectionType connectionType;
|
||||
};
|
||||
|
||||
struct EstablishConnectionResponse : public Event
|
||||
class EstablishConnectionResponse : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
enum ErrorReason {
|
||||
NoError = 0,
|
||||
MongoConnection = 1,
|
||||
MongoAuth = 2,
|
||||
MongoSslConnection = 3
|
||||
MongoConnection = 0,
|
||||
MongoAuth = 1,
|
||||
MongoSslConnection = 2
|
||||
};
|
||||
|
||||
EstablishConnectionResponse(QObject *sender, const ConnectionInfo &info, ConnectionType connectionType,
|
||||
const ReplicaSet& replicaSet) :
|
||||
const mongo::HostAndPort& repPrimary, const std::vector<bool>& repMembersHealths) :
|
||||
Event(sender),
|
||||
info(info),
|
||||
_info(info),
|
||||
connectionType(connectionType),
|
||||
replicaSet(replicaSet)
|
||||
_repPrimary(repPrimary),
|
||||
_repMembersHealths(repMembersHealths)
|
||||
{}
|
||||
|
||||
EstablishConnectionResponse(QObject *sender, const EventError &error, ConnectionType connectionType,
|
||||
ConnectionInfo const& info, const ReplicaSet& replicaSet, ErrorReason errorReason) :
|
||||
EstablishConnectionResponse(QObject *sender, const EventError &error, ConnectionType connectionType, ErrorReason errorReason) :
|
||||
Event(sender, error),
|
||||
info(info),
|
||||
_info(),
|
||||
connectionType(connectionType),
|
||||
errorReason(errorReason),
|
||||
replicaSet(replicaSet)
|
||||
{}
|
||||
errorReason(errorReason) {}
|
||||
|
||||
ConnectionInfo const info;
|
||||
ConnectionType const connectionType;
|
||||
ErrorReason const errorReason = NoError;
|
||||
ReplicaSet const replicaSet;
|
||||
// Getters
|
||||
const ConnectionInfo &info() const { return _info; }
|
||||
const mongo::HostAndPort& getRepPrimary() const { return _repPrimary; }
|
||||
const std::vector<bool>& getRepMembersHealths() const { return _repMembersHealths; }
|
||||
|
||||
const ConnectionInfo _info;
|
||||
ConnectionType connectionType;
|
||||
ErrorReason errorReason;
|
||||
mongo::HostAndPort _repPrimary;
|
||||
std::vector<bool> _repMembersHealths; // todo: vector of host and health pair
|
||||
};
|
||||
|
||||
struct ReplicaSetRefreshed : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
ReplicaSetRefreshed(QObject *sender) :
|
||||
Event(sender) {}
|
||||
|
||||
ReplicaSetRefreshed(QObject *sender, const EventError &error, ReplicaSet const& replicaSet) :
|
||||
Event(sender, error), replicaSet(replicaSet) {}
|
||||
|
||||
ReplicaSet const replicaSet;
|
||||
};
|
||||
|
||||
struct RefreshReplicaSetFolderRequest : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
RefreshReplicaSetFolderRequest(QObject *sender, bool expanded) :
|
||||
Event(sender), expanded(expanded) {}
|
||||
|
||||
bool const expanded = false;
|
||||
};
|
||||
|
||||
struct RefreshReplicaSetFolderResponse : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
// Primary is reachable
|
||||
RefreshReplicaSetFolderResponse(QObject *sender, ReplicaSet const& replicaSet, bool expanded) :
|
||||
Event(sender), replicaSet(replicaSet), expanded(expanded) {}
|
||||
|
||||
// Primary is unreachable, secondary(ies) might be reachable
|
||||
RefreshReplicaSetFolderResponse(QObject *sender, ReplicaSet const& replicaSet, bool expanded,
|
||||
const EventError &error) :
|
||||
Event(sender, error), replicaSet(replicaSet), expanded(expanded) {}
|
||||
|
||||
ReplicaSet const replicaSet;
|
||||
bool const expanded = false;
|
||||
};
|
||||
|
||||
struct ReplicaSetFolderLoading : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
ReplicaSetFolderLoading(QObject *sender) :
|
||||
Event(sender) {}
|
||||
};
|
||||
|
||||
struct ReplicaSetFolderRefreshed : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
ReplicaSetFolderRefreshed(QObject *sender, bool expanded) :
|
||||
Event(sender), expanded(expanded) {}
|
||||
|
||||
ReplicaSetFolderRefreshed(QObject *sender, const EventError &error, bool expanded) :
|
||||
Event(sender, error), expanded(expanded) {}
|
||||
|
||||
ReplicaSetFolderRefreshed(QObject *sender, const EventError &error, ReplicaSet const& replicaSet,
|
||||
bool expanded) :
|
||||
Event(sender, error), replicaSet(replicaSet), expanded(expanded) {}
|
||||
|
||||
ReplicaSet const replicaSet;
|
||||
bool const expanded = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief LoadDatabaseNames
|
||||
@@ -414,7 +349,7 @@ namespace Robomongo
|
||||
InsertDocumentResponse(QObject *sender) :
|
||||
Event(sender) {}
|
||||
|
||||
InsertDocumentResponse(QObject *sender, EventError const& error) :
|
||||
InsertDocumentResponse(QObject *sender, const EventError &error) :
|
||||
Event(sender, error) {}
|
||||
};
|
||||
|
||||
@@ -422,46 +357,37 @@ namespace Robomongo
|
||||
* @brief Remove Document
|
||||
*/
|
||||
|
||||
enum class RemoveDocumentCount { ONE, MULTI, ALL };
|
||||
|
||||
class RemoveDocumentRequest : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
public:
|
||||
RemoveDocumentRequest(QObject *sender, mongo::Query query, const MongoNamespace &ns,
|
||||
RemoveDocumentCount removeCount, int index) :
|
||||
RemoveDocumentRequest(QObject *sender, mongo::Query query, const MongoNamespace &ns, bool justOne = true) :
|
||||
Event(sender),
|
||||
_query(query),
|
||||
_ns(ns),
|
||||
_removeCount(removeCount),
|
||||
_index(index) {}
|
||||
_justOne(justOne) {}
|
||||
|
||||
mongo::Query query() const { return _query; }
|
||||
MongoNamespace ns() const { return _ns; }
|
||||
RemoveDocumentCount removeCount() const { return _removeCount; }
|
||||
int index() const { return _index; }
|
||||
bool justOne() const { return _justOne; }
|
||||
|
||||
private:
|
||||
mongo::Query const _query;
|
||||
MongoNamespace const _ns;
|
||||
RemoveDocumentCount const _removeCount;
|
||||
// if this is a multi remove, this is the index of current document deleted. 0 for first document.
|
||||
int const _index;
|
||||
mongo::Query _query;
|
||||
const MongoNamespace _ns;
|
||||
bool _justOne;
|
||||
};
|
||||
|
||||
struct RemoveDocumentResponse : public Event
|
||||
class RemoveDocumentResponse : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
RemoveDocumentResponse(QObject *sender, RemoveDocumentCount removeCount, int index) :
|
||||
Event(sender), removeCount(removeCount), index(index) {}
|
||||
public:
|
||||
RemoveDocumentResponse(QObject *sender) :
|
||||
Event(sender) {}
|
||||
|
||||
RemoveDocumentResponse(QObject *sender, const EventError &error, RemoveDocumentCount removeCount, int index) :
|
||||
Event(sender, error), removeCount(removeCount), index(index) {}
|
||||
|
||||
RemoveDocumentCount const removeCount;
|
||||
int const index;
|
||||
RemoveDocumentResponse(QObject *sender, const EventError &error) :
|
||||
Event(sender, error) {}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -480,49 +406,52 @@ namespace Robomongo
|
||||
std::string database() const { return _database; }
|
||||
|
||||
private:
|
||||
std::string const _database;
|
||||
std::string _database;
|
||||
};
|
||||
|
||||
struct CreateDatabaseResponse : public Event
|
||||
class CreateDatabaseResponse : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
CreateDatabaseResponse(QObject *sender, const std::string &database) :
|
||||
Event(sender), database(database) {}
|
||||
public:
|
||||
CreateDatabaseResponse(QObject *sender) :
|
||||
Event(sender) {}
|
||||
|
||||
CreateDatabaseResponse(QObject *sender, const std::string &database, const EventError &error) :
|
||||
Event(sender, error), database(database) {}
|
||||
|
||||
std::string const database;
|
||||
CreateDatabaseResponse(QObject *sender, const EventError &error) :
|
||||
Event(sender, error) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Drop Database
|
||||
*/
|
||||
|
||||
struct DropDatabaseRequest : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
DropDatabaseRequest(QObject *sender, const std::string &database) :
|
||||
Event(sender), database(database) {}
|
||||
|
||||
std::string const database;
|
||||
};
|
||||
|
||||
struct DropDatabaseResponse : public Event
|
||||
class DropDatabaseRequest : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
public:
|
||||
DropDatabaseResponse(QObject *sender, const std::string &database) :
|
||||
Event(sender), database(database) {}
|
||||
DropDatabaseRequest(QObject *sender, const std::string &database) :
|
||||
Event(sender),
|
||||
_database(database) {}
|
||||
|
||||
DropDatabaseResponse(QObject *sender, const std::string &database, const EventError &error) :
|
||||
Event(sender, error), database(database) {}
|
||||
std::string database() const { return _database; }
|
||||
|
||||
std::string const database;
|
||||
private:
|
||||
std::string _database;
|
||||
};
|
||||
|
||||
class DropDatabaseResponse : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
public:
|
||||
DropDatabaseResponse(QObject *sender) :
|
||||
Event(sender) {}
|
||||
|
||||
DropDatabaseResponse(QObject *sender, const EventError &error) :
|
||||
Event(sender, error) {}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -543,31 +472,30 @@ namespace Robomongo
|
||||
Event(sender), _ns(ns), _extraOptions(extraOptions),
|
||||
_size(size), _capped(capped), _maxDocNum(maxDocNum) {}
|
||||
|
||||
MongoNamespace ns() const { return _ns; }
|
||||
MongoNamespace getNs() const { return _ns; }
|
||||
long long getSize() const { return _size; }
|
||||
bool getCapped() const { return _capped; }
|
||||
int getMaxDocNum() const { return _maxDocNum; }
|
||||
const mongo::BSONObj getExtraOptions() const { return _extraOptions; }
|
||||
|
||||
private:
|
||||
MongoNamespace const _ns;
|
||||
long long const _size;
|
||||
bool const _capped;
|
||||
int const _maxDocNum;
|
||||
mongo::BSONObj const _extraOptions;
|
||||
const MongoNamespace _ns;
|
||||
const long long _size;
|
||||
const bool _capped;
|
||||
const int _maxDocNum;
|
||||
const mongo::BSONObj _extraOptions;
|
||||
};
|
||||
|
||||
struct CreateCollectionResponse : public Event
|
||||
class CreateCollectionResponse : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
CreateCollectionResponse(QObject *sender, std::string const& collection) :
|
||||
Event(sender), collection(collection) {}
|
||||
public:
|
||||
CreateCollectionResponse(QObject *sender) :
|
||||
Event(sender) {}
|
||||
|
||||
CreateCollectionResponse(QObject *sender, std::string const& collection, const EventError &error) :
|
||||
Event(sender, error), collection(collection) {}
|
||||
|
||||
std::string const collection;
|
||||
CreateCollectionResponse(QObject *sender, const EventError &error) :
|
||||
Event(sender, error) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -591,18 +519,16 @@ namespace Robomongo
|
||||
MongoNamespace _ns;
|
||||
};
|
||||
|
||||
struct DropCollectionResponse : public Event
|
||||
class DropCollectionResponse : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
public:
|
||||
DropCollectionResponse(QObject *sender, std::string const& collection) :
|
||||
Event(sender), collection(collection) {}
|
||||
DropCollectionResponse(QObject *sender) :
|
||||
Event(sender) {}
|
||||
|
||||
DropCollectionResponse(QObject *sender, std::string const& collection, const EventError &error) :
|
||||
Event(sender, error), collection(collection) {}
|
||||
|
||||
std::string const collection;
|
||||
DropCollectionResponse(QObject *sender, const EventError &error) :
|
||||
Event(sender, error) {}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -623,23 +549,20 @@ namespace Robomongo
|
||||
std::string newCollection() const { return _newCollection; }
|
||||
|
||||
private:
|
||||
MongoNamespace const _ns;
|
||||
std::string const _newCollection;
|
||||
MongoNamespace _ns;
|
||||
std::string _newCollection;
|
||||
};
|
||||
|
||||
struct RenameCollectionResponse : public Event
|
||||
class RenameCollectionResponse : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
RenameCollectionResponse(QObject *sender, std::string const& oldCollection,
|
||||
std::string const& newCollection) :
|
||||
Event(sender), oldCollection(oldCollection), newCollection(newCollection) {}
|
||||
public:
|
||||
RenameCollectionResponse(QObject *sender) :
|
||||
Event(sender) {}
|
||||
|
||||
RenameCollectionResponse(QObject *sender, const EventError &error) :
|
||||
Event(sender, error) {}
|
||||
|
||||
std::string const oldCollection;
|
||||
std::string const newCollection;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -660,24 +583,20 @@ namespace Robomongo
|
||||
std::string newCollection() const { return _newCollection; }
|
||||
|
||||
private:
|
||||
MongoNamespace const _ns;
|
||||
std::string const _newCollection;
|
||||
MongoNamespace _ns;
|
||||
std::string _newCollection;
|
||||
};
|
||||
|
||||
struct DuplicateCollectionResponse : public Event
|
||||
class DuplicateCollectionResponse : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
public:
|
||||
DuplicateCollectionResponse(QObject *sender, std::string const& sourceCollection,
|
||||
std::string const& duplicateCollection) :
|
||||
Event(sender), sourceCollection(sourceCollection), duplicateCollection(duplicateCollection) {}
|
||||
DuplicateCollectionResponse(QObject *sender) :
|
||||
Event(sender) {}
|
||||
|
||||
DuplicateCollectionResponse(QObject *sender, std::string const& sourceCollection, const EventError &error) :
|
||||
Event(sender, error), sourceCollection(sourceCollection) {}
|
||||
|
||||
std::string const sourceCollection;
|
||||
std::string const duplicateCollection;
|
||||
DuplicateCollectionResponse(QObject *sender, const EventError &error) :
|
||||
Event(sender, error) {}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -742,17 +661,16 @@ namespace Robomongo
|
||||
bool _overwrite;
|
||||
};
|
||||
|
||||
struct CreateUserResponse : public Event
|
||||
class CreateUserResponse : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
CreateUserResponse(QObject *sender, std::string const& userName) :
|
||||
Event(sender), userName(userName) {}
|
||||
public:
|
||||
CreateUserResponse(QObject *sender) :
|
||||
Event(sender) {}
|
||||
|
||||
CreateUserResponse(QObject *sender, std::string const& userName, const EventError &error) :
|
||||
Event(sender, error), userName(userName) {}
|
||||
|
||||
std::string const userName;
|
||||
CreateUserResponse(QObject *sender, const EventError &error) :
|
||||
Event(sender, error) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -765,31 +683,29 @@ namespace Robomongo
|
||||
R_EVENT
|
||||
|
||||
public:
|
||||
DropUserRequest(QObject *sender, const std::string &database, const mongo::OID &id,
|
||||
std::string const& username) :
|
||||
Event(sender), _database(database), _id(id), _username(username) {}
|
||||
DropUserRequest(QObject *sender, const std::string &database, const mongo::OID &id) :
|
||||
Event(sender),
|
||||
_database(database),
|
||||
_id(id) {}
|
||||
|
||||
std::string database() const { return _database; }
|
||||
mongo::OID id() const { return _id; }
|
||||
std::string username() const { return _username; }
|
||||
|
||||
private:
|
||||
std::string _database;
|
||||
mongo::OID _id;
|
||||
std::string const _username;
|
||||
};
|
||||
|
||||
struct DropUserResponse : public Event
|
||||
class DropUserResponse : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
DropUserResponse(QObject *sender, std::string const& username) :
|
||||
Event(sender), username(username) {}
|
||||
public:
|
||||
DropUserResponse(QObject *sender) :
|
||||
Event(sender) {}
|
||||
|
||||
DropUserResponse(QObject *sender, std::string const& username, const EventError &error) :
|
||||
Event(sender, error), username(username) {}
|
||||
|
||||
std::string const username;
|
||||
DropUserResponse(QObject *sender, const EventError &error) :
|
||||
Event(sender, error) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -822,21 +738,19 @@ namespace Robomongo
|
||||
bool _overwrite;
|
||||
};
|
||||
|
||||
struct CreateFunctionResponse : public Event
|
||||
class CreateFunctionResponse : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
enum Operation { NewFunction, NameUpdate, CodeUpdate }; // todo
|
||||
|
||||
CreateFunctionResponse(QObject *sender, std::string const& functionName) :
|
||||
Event(sender), functionName(functionName) {}
|
||||
public:
|
||||
CreateFunctionResponse(QObject *sender) :
|
||||
Event(sender) {}
|
||||
|
||||
CreateFunctionResponse(QObject *sender, std::string const& functionName, const EventError &error) :
|
||||
Event(sender, error), functionName(functionName) {}
|
||||
|
||||
std::string const functionName;
|
||||
CreateFunctionResponse(QObject *sender, const EventError &error) :
|
||||
Event(sender, error) {}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Drop Function
|
||||
*/
|
||||
@@ -846,30 +760,29 @@ namespace Robomongo
|
||||
R_EVENT
|
||||
|
||||
public:
|
||||
DropFunctionRequest(QObject *sender, const std::string &database, const std::string &funcName) :
|
||||
DropFunctionRequest(QObject *sender, const std::string &database, const std::string &name) :
|
||||
Event(sender),
|
||||
_database(database),
|
||||
_functionName(funcName) {}
|
||||
_name(name) {}
|
||||
|
||||
std::string database() const { return _database; }
|
||||
std::string functionName() const { return _functionName; }
|
||||
std::string name() const { return _name; }
|
||||
|
||||
private:
|
||||
std::string _database;
|
||||
std::string _functionName;
|
||||
std::string _name;
|
||||
};
|
||||
|
||||
struct DropFunctionResponse : public Event
|
||||
class DropFunctionResponse : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
DropFunctionResponse(QObject *sender, const std::string &functionName) :
|
||||
Event(sender), functionName(functionName) {}
|
||||
public:
|
||||
DropFunctionResponse(QObject *sender) :
|
||||
Event(sender) {}
|
||||
|
||||
DropFunctionResponse(QObject *sender, const std::string &functionName, const EventError &error) :
|
||||
Event(sender, error), functionName(functionName) {}
|
||||
|
||||
std::string const functionName;
|
||||
DropFunctionResponse(QObject *sender, const EventError &error) :
|
||||
Event(sender, error) {}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1026,19 +939,17 @@ namespace Robomongo
|
||||
|
||||
// class ScriptExecute
|
||||
|
||||
struct ConnectionEstablishedEvent : public Event
|
||||
class ConnectionEstablishedEvent : public Event
|
||||
{
|
||||
R_EVENT
|
||||
|
||||
ConnectionEstablishedEvent(MongoServer *server, ConnectionType type, ConnectionInfo connInfo) :
|
||||
ConnectionEstablishedEvent(MongoServer *server, ConnectionType type) :
|
||||
Event((QObject *)server),
|
||||
server(server),
|
||||
connectionType(type),
|
||||
connInfo(connInfo) { }
|
||||
connectionType(type) { }
|
||||
|
||||
MongoServer *server;
|
||||
ConnectionType const connectionType;
|
||||
ConnectionInfo const connInfo;
|
||||
ConnectionType connectionType;
|
||||
};
|
||||
|
||||
class DatabaseListLoadedEvent : public Event
|
||||
|
||||
@@ -17,19 +17,15 @@ namespace Robomongo
|
||||
_languageOverride(languageOverride),
|
||||
_textWeights(textWeights) {}
|
||||
|
||||
ConnectionInfo::ConnectionInfo(std::string const& uuid) :
|
||||
ConnectionInfo::ConnectionInfo() :
|
||||
_address(),
|
||||
_databases(),
|
||||
_version(0.0f),
|
||||
_uuid(uuid)
|
||||
{}
|
||||
_version(0.0f) {}
|
||||
|
||||
ConnectionInfo::ConnectionInfo(const std::string &address, const std::vector<std::string> &databases,
|
||||
float version, const std::string& storageEngine, std::string const& uuid) :
|
||||
float version, const std::string& storageEngine) :
|
||||
_address(address),
|
||||
_databases(databases),
|
||||
_version(version),
|
||||
_storageEngineType(storageEngine),
|
||||
_uuid(uuid)
|
||||
{}
|
||||
_storageEngineType(storageEngine) {}
|
||||
}
|
||||
|
||||
@@ -34,13 +34,11 @@ namespace Robomongo
|
||||
|
||||
struct ConnectionInfo
|
||||
{
|
||||
ConnectionInfo(std::string const& uuid);
|
||||
ConnectionInfo(const std::string &address, const std::vector<std::string> &databases, float version,
|
||||
const std::string& storageEngine, std::string const& uuid);
|
||||
ConnectionInfo();
|
||||
ConnectionInfo(const std::string &address, const std::vector<std::string> &databases, float version, const std::string& storageEngine);
|
||||
const std::string _address;
|
||||
const std::vector<std::string> _databases;
|
||||
const float _version;
|
||||
const std::string _storageEngineType;
|
||||
std::string const _uuid;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -108,10 +108,9 @@ namespace Robomongo
|
||||
MongoNamespace ns(dbName, "system.users");
|
||||
mongo::BSONObj obj = user.toBson();
|
||||
|
||||
if (!overwrite) { // create new user
|
||||
if (!overwrite) {
|
||||
_dbclient->insert(ns.toString(), obj);
|
||||
}
|
||||
else { // update existing user
|
||||
} else {
|
||||
mongo::BSONElement id = obj.getField("_id");
|
||||
mongo::BSONObjBuilder builder;
|
||||
builder.append(id);
|
||||
@@ -120,10 +119,6 @@ namespace Robomongo
|
||||
|
||||
_dbclient->update(ns.toString(), query, obj, true, false);
|
||||
}
|
||||
|
||||
std::string errorStr = _dbclient->getLastError();
|
||||
if (!errorStr.empty())
|
||||
throw mongo::DBException(errorStr, 0);
|
||||
}
|
||||
|
||||
void MongoClient::dropUser(const std::string &dbName, const mongo::OID &id)
|
||||
@@ -136,10 +131,6 @@ namespace Robomongo
|
||||
mongo::Query query(bsonQuery);
|
||||
|
||||
_dbclient->remove(ns.toString(), query, true);
|
||||
|
||||
std::string errorStr = _dbclient->getLastError();
|
||||
if (!errorStr.empty())
|
||||
throw mongo::DBException(errorStr, 0);
|
||||
}
|
||||
|
||||
std::vector<MongoFunction> MongoClient::getFunctions(const std::string &dbName)
|
||||
@@ -302,46 +293,36 @@ namespace Robomongo
|
||||
_dbclient->dropIndex(collection.ns().toString(), indexName);
|
||||
}
|
||||
|
||||
void MongoClient::createFunction(const std::string &dbName, const MongoFunction &fun,
|
||||
const std::string &existingFunctionName /* = QString() */)
|
||||
void MongoClient::createFunction(const std::string &dbName, const MongoFunction &fun, const std::string &existingFunctionName /* = QString() */)
|
||||
{
|
||||
MongoNamespace ns(dbName, "system.js");
|
||||
mongo::BSONObj obj = fun.toBson();
|
||||
|
||||
if (existingFunctionName.empty()) { // create new function
|
||||
if (existingFunctionName.empty()) { // this is insert
|
||||
_dbclient->insert(ns.toString(), obj);
|
||||
std::string errorStr = _dbclient->getLastError();
|
||||
if (!errorStr.empty())
|
||||
throw mongo::DBException(errorStr, 0);
|
||||
} else { // this is update
|
||||
|
||||
std::string name = fun.name();
|
||||
|
||||
if (existingFunctionName == name) { // update existing function code
|
||||
if (existingFunctionName == name) {
|
||||
mongo::BSONObjBuilder builder;
|
||||
builder.append("_id", name);
|
||||
mongo::BSONObj bsonQuery = builder.obj();
|
||||
mongo::Query query(bsonQuery);
|
||||
|
||||
_dbclient->update(ns.toString(), query, obj, true, false);
|
||||
std::string errorStr = _dbclient->getLastError();
|
||||
if (!errorStr.empty())
|
||||
throw mongo::DBException(errorStr, 0);
|
||||
} else { // update function name (remove & insert)
|
||||
} else {
|
||||
_dbclient->insert(ns.toString(), obj);
|
||||
std::string errorStr = _dbclient->getLastError();
|
||||
std::string res = _dbclient->getLastError();
|
||||
|
||||
// if no errors
|
||||
if (errorStr.empty()) {
|
||||
if (res.empty()) {
|
||||
mongo::BSONObjBuilder builder;
|
||||
builder.append("_id", existingFunctionName);
|
||||
mongo::BSONObj bsonQuery = builder.obj();
|
||||
mongo::Query query(bsonQuery);
|
||||
_dbclient->remove(ns.toString(), query, true);
|
||||
}
|
||||
else {
|
||||
throw mongo::DBException(errorStr, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -356,9 +337,6 @@ namespace Robomongo
|
||||
mongo::Query query(bsonQuery);
|
||||
|
||||
_dbclient->remove(ns.toString(), query, true);
|
||||
std::string errorStr = _dbclient->getLastError();
|
||||
if (!errorStr.empty())
|
||||
throw mongo::DBException(errorStr, 0);
|
||||
}
|
||||
|
||||
void MongoClient::createDatabase(const std::string &dbName)
|
||||
@@ -373,7 +351,7 @@ namespace Robomongo
|
||||
|
||||
// If <dbName>.temp already exists, stop.
|
||||
if (_dbclient->exists(ns.toString()))
|
||||
throw mongo::DBException(dbName + ".temp already exists.", 0);
|
||||
return;
|
||||
|
||||
// Building { _id : "temp" } document
|
||||
mongo::BSONObjBuilder builder;
|
||||
@@ -382,9 +360,6 @@ namespace Robomongo
|
||||
|
||||
// Insert this document
|
||||
_dbclient->insert(ns.toString(), obj);
|
||||
std::string errorStr = _dbclient->getLastError();
|
||||
if (!errorStr.empty())
|
||||
throw mongo::DBException(errorStr, 0);
|
||||
|
||||
// Drop temp collection
|
||||
_dbclient->dropCollection(ns.toString());
|
||||
@@ -392,18 +367,10 @@ namespace Robomongo
|
||||
|
||||
void MongoClient::dropDatabase(const std::string &dbName)
|
||||
{
|
||||
mongo::BSONObj result;
|
||||
if (!_dbclient->dropDatabase(dbName, &result)) {
|
||||
std::string errStr = result.getStringField("errmsg");
|
||||
if (errStr.empty())
|
||||
errStr = "Failed to get error message.";
|
||||
|
||||
throw mongo::DBException(errStr, 0);
|
||||
}
|
||||
_dbclient->dropDatabase(dbName);
|
||||
}
|
||||
|
||||
void MongoClient::createCollection(const std::string& ns, long long size, bool capped, int max,
|
||||
const mongo::BSONObj& extraOptions, mongo::BSONObj* info)
|
||||
void MongoClient::createCollection(const std::string& ns, long long size, bool capped, int max, const mongo::BSONObj& extraOptions, mongo::BSONObj* info)
|
||||
{
|
||||
verify(!capped || size);
|
||||
mongo::BSONObj o;
|
||||
@@ -423,19 +390,7 @@ namespace Robomongo
|
||||
}
|
||||
b.appendElements(extraOptions);
|
||||
|
||||
if (!_dbclient->exists(ns)) {
|
||||
mongo::BSONObj result;
|
||||
if (!_dbclient->runCommand(db.c_str(), b.done(), result)) {
|
||||
std::string errStr = result.getStringField("errmsg");
|
||||
if (errStr.empty())
|
||||
errStr = "Failed to get error message.";
|
||||
|
||||
throw mongo::DBException(errStr, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw mongo::DBException("Collection with same name already exists.", 0);
|
||||
}
|
||||
_dbclient->runCommand(db.c_str(), b.done(), *info);
|
||||
}
|
||||
|
||||
void MongoClient::renameCollection(const MongoNamespace &ns, const std::string &newCollectionName)
|
||||
@@ -449,38 +404,18 @@ namespace Robomongo
|
||||
command.append("to", to.toString());
|
||||
|
||||
mongo::BSONObj result;
|
||||
if (!_dbclient->runCommand("admin", command.obj(), result)) { // this command should be run against "admin" db
|
||||
std::string errStr = result.getStringField("errmsg");
|
||||
if (errStr.empty())
|
||||
errStr = "Failed to get error message.";
|
||||
|
||||
throw mongo::DBException(errStr, 0);
|
||||
}
|
||||
_dbclient->runCommand("admin", command.obj(), result); // this command should be run against "admin" db
|
||||
}
|
||||
|
||||
void MongoClient::duplicateCollection(const MongoNamespace &ns, const std::string &newCollectionName)
|
||||
{
|
||||
MongoNamespace sourceCollection(ns);
|
||||
MongoNamespace newCollection(ns.databaseName(), newCollectionName);
|
||||
MongoNamespace from(ns);
|
||||
MongoNamespace to(ns.databaseName(), newCollectionName);
|
||||
|
||||
if (!_dbclient->exists(newCollection.toString())) {
|
||||
mongo::BSONObj result;
|
||||
// todo: Issue #1258 : Duplicate Collection should support advanced collection options.
|
||||
// _dbclient->createCollection() should be called with properties of source collection
|
||||
// not with default parameters as below.
|
||||
if (!_dbclient->createCollection(newCollection.toString(), 0, false, 0, &result)) {
|
||||
std::string errStr = result.getStringField("errmsg");
|
||||
if (errStr.empty())
|
||||
errStr = "Failed to get error message.";
|
||||
if (!_dbclient->exists(to.toString()))
|
||||
_dbclient->createCollection(to.toString());
|
||||
|
||||
throw mongo::DBException(errStr, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw mongo::DBException("Collection with same name already exists.", 0);
|
||||
}
|
||||
|
||||
std::unique_ptr<mongo::DBClientCursor> cursor(_dbclient->query(sourceCollection.toString(), mongo::Query()));
|
||||
std::unique_ptr<mongo::DBClientCursor> cursor(_dbclient->query(from.toString(), mongo::Query()));
|
||||
|
||||
// Cursor may be NULL, it means we have connectivity problem
|
||||
if (!cursor)
|
||||
@@ -488,12 +423,11 @@ namespace Robomongo
|
||||
|
||||
while (cursor->more()) {
|
||||
mongo::BSONObj bsonObj = cursor->next();
|
||||
_dbclient->insert(newCollection.toString(), bsonObj);
|
||||
_dbclient->insert(to.toString(), bsonObj);
|
||||
}
|
||||
}
|
||||
|
||||
void MongoClient::copyCollectionToDiffServer(mongo::DBClientBase *const fromServ, const MongoNamespace &from,
|
||||
const MongoNamespace &to)
|
||||
void MongoClient::copyCollectionToDiffServer(mongo::DBClientBase *const fromServ, const MongoNamespace &from, const MongoNamespace &to)
|
||||
{
|
||||
if (!_dbclient->exists(to.toString()))
|
||||
_dbclient->createCollection(to.toString());
|
||||
@@ -512,19 +446,7 @@ namespace Robomongo
|
||||
|
||||
void MongoClient::dropCollection(const MongoNamespace &ns)
|
||||
{
|
||||
if (_dbclient->exists(ns.toString())) {
|
||||
mongo::BSONObj result;
|
||||
if (!_dbclient->dropCollection(ns.toString(), &result)) {
|
||||
std::string errStr = result.getStringField("errmsg");
|
||||
if (errStr.empty())
|
||||
errStr = "Failed to get error message.";
|
||||
|
||||
throw mongo::DBException(errStr, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw mongo::DBException("Collection does not exist.", 0);
|
||||
}
|
||||
_dbclient->dropCollection(ns.toString());
|
||||
}
|
||||
|
||||
void MongoClient::insertDocument(const mongo::BSONObj &obj, const MongoNamespace &ns)
|
||||
@@ -602,10 +524,11 @@ namespace Robomongo
|
||||
std::vector<MongoCollectionInfo> MongoClient::runCollStatsCommand(const std::vector<std::string> &namespaces)
|
||||
{
|
||||
std::vector<MongoCollectionInfo> infos;
|
||||
for (auto const& ns : namespaces) {
|
||||
MongoCollectionInfo info = runCollStatsCommand(ns);
|
||||
if (info.ns().isValid())
|
||||
for (std::vector<std::string>::const_iterator it = namespaces.begin(); it != namespaces.end(); ++it) {
|
||||
MongoCollectionInfo info = runCollStatsCommand(*it);
|
||||
if (info.ns().isValid()) {
|
||||
infos.push_back(info);
|
||||
}
|
||||
}
|
||||
return infos;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "robomongo/core/mongodb/MongoWorker.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <QThread>
|
||||
|
||||
#include "mongo/client/global_conn_pool.h"
|
||||
@@ -21,18 +19,17 @@
|
||||
#include "robomongo/core/settings/CredentialSettings.h"
|
||||
#include "robomongo/core/settings/SettingsManager.h"
|
||||
#include "robomongo/core/settings/SslSettings.h"
|
||||
#include "robomongo/core/utils/BsonUtils.h"
|
||||
#include "robomongo/core/utils/Logger.h"
|
||||
#include "robomongo/core/utils/QtUtils.h"
|
||||
#include "robomongo/utils/string_operations.h"
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
std::string const PRIMARY_UNREACHABLE = "Replica set's primary is unreachable.";
|
||||
|
||||
MongoWorker::MongoWorker(ConnectionSettings *connection, bool isLoadMongoRcJs, int batchSize,
|
||||
int mongoTimeoutSec, int shellTimeoutSec, QObject *parent) : QObject(parent),
|
||||
_scriptEngine(nullptr),
|
||||
_connSettings(connection),
|
||||
_scriptEngine(NULL),
|
||||
_dbclient(nullptr),
|
||||
_dbclientRepSet(nullptr),
|
||||
_isAdmin(true),
|
||||
_isLoadMongoRcJs(isLoadMongoRcJs),
|
||||
_batchSize(batchSize),
|
||||
@@ -40,10 +37,7 @@ namespace Robomongo
|
||||
_dbAutocompleteCacheTimerId(-1),
|
||||
_mongoTimeoutSec(mongoTimeoutSec),
|
||||
_shellTimeoutSec(shellTimeoutSec),
|
||||
_isQuiting(0),
|
||||
_dbclient(nullptr),
|
||||
_dbclientRepSet(nullptr),
|
||||
_connSettings(connection)
|
||||
_isQuiting(0)
|
||||
{
|
||||
_thread = new QThread();
|
||||
moveToThread(_thread);
|
||||
@@ -59,7 +53,8 @@ namespace Robomongo
|
||||
return;
|
||||
}
|
||||
|
||||
if (_dbAutocompleteCacheTimerId == event->timerId() && !_scriptEngine) {
|
||||
if (_dbAutocompleteCacheTimerId == event->timerId() &&
|
||||
_scriptEngine != NULL) {
|
||||
_scriptEngine->invalidateDbCollectionsCache();
|
||||
return;
|
||||
}
|
||||
@@ -69,11 +64,16 @@ namespace Robomongo
|
||||
{
|
||||
try {
|
||||
if (_dbclient) {
|
||||
pingDatabase(_dbclient.get());
|
||||
}
|
||||
|
||||
if (_dbclientRepSet) {
|
||||
pingDatabase(_dbclientRepSet.get());
|
||||
// Building { ping: 1 }
|
||||
mongo::BSONObjBuilder command;
|
||||
command.append("ping", 1);
|
||||
mongo::BSONObj result;
|
||||
std::string authBase = getAuthBase();
|
||||
if (authBase.empty()) {
|
||||
_dbclient->runCommand("admin", command.obj(), result);
|
||||
} else {
|
||||
_dbclient->runCommand(authBase, command.obj(), result);
|
||||
}
|
||||
}
|
||||
|
||||
if (_scriptEngine) {
|
||||
@@ -81,23 +81,21 @@ namespace Robomongo
|
||||
}
|
||||
|
||||
} catch(std::exception &ex) {
|
||||
LOG_MSG("Failed to ping the server. MongoWorker::keepAlive() failed. " + std::string(ex.what()),
|
||||
mongo::logger::LogSeverity::Error());
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
void MongoWorker::init()
|
||||
{
|
||||
try {
|
||||
_scriptEngine.reset(new ScriptEngine(_connSettings, _shellTimeoutSec));
|
||||
_scriptEngine = new ScriptEngine(_connSettings, _shellTimeoutSec);
|
||||
_scriptEngine->init(_isLoadMongoRcJs);
|
||||
_scriptEngine->use(_connSettings->defaultDatabase());
|
||||
_scriptEngine->setBatchSize(_batchSize);
|
||||
_timerId = startTimer(pingTimeMs);
|
||||
_dbAutocompleteCacheTimerId = startTimer(30000);
|
||||
} catch (const std::exception &ex) {
|
||||
LOG_MSG("Failed to initialize MongoWorker. " + std::string(ex.what()),
|
||||
mongo::logger::LogSeverity::Error());
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +119,7 @@ namespace Robomongo
|
||||
killTimer(_dbAutocompleteCacheTimerId);
|
||||
|
||||
delete _connSettings;
|
||||
delete _scriptEngine;
|
||||
|
||||
// QThread "_thread" and MongoWorker itself will be deleted later
|
||||
// (see MongoWorker() constructor)
|
||||
@@ -135,75 +134,32 @@ namespace Robomongo
|
||||
/**
|
||||
* @brief Initiate connection to MongoDB
|
||||
*/
|
||||
bool MongoWorker::handle(EstablishConnectionRequest *event)
|
||||
void MongoWorker::handle(EstablishConnectionRequest *event)
|
||||
{
|
||||
QMutexLocker lock(&_firstConnectionMutex);
|
||||
|
||||
std::unique_ptr<ReplicaSet> repSetInfo(new ReplicaSet);
|
||||
auto errorCode = EventError::ErrorCode::Unknown;
|
||||
|
||||
try {
|
||||
mongo::DBClientBase *conn = getConnection(true);
|
||||
|
||||
// --- Connection failed for single server & replica set (no member of the set is reachable)
|
||||
if (!conn)
|
||||
{
|
||||
if (conn == NULL) {
|
||||
// Protection by default value: Logically/ideally, this error should never be seen.
|
||||
auto errorReason = std::string("Connection failure: Unknown error.");
|
||||
|
||||
if (_connSettings->sslSettings()->sslEnabled()) {
|
||||
if (_connSettings->sslSettings()->sslEnabled())
|
||||
{
|
||||
// Note: Currently mongo-shell does not provide any interface to fetch actual error details
|
||||
// for some SSL connection failures that's why we are unable to show exact error here.
|
||||
errorReason = "SSL tunnel failure: Network is unreachable or SSL connection rejected by server.";
|
||||
}
|
||||
else { // Non-SSL connections
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
errorReason = "No member of the set is reachable.";
|
||||
std::vector<std::pair<std::string, bool>> membersAndHealths;
|
||||
for (auto const& member : _connSettings->replicaSetSettings()->members()) {
|
||||
membersAndHealths.push_back({ member, false });
|
||||
}
|
||||
repSetInfo.reset(new ReplicaSet("", mongo::HostAndPort(), membersAndHealths,
|
||||
"No member of the set is reachable."));
|
||||
}
|
||||
else // single server
|
||||
errorReason = "Network is unreachable.";
|
||||
else
|
||||
{
|
||||
errorReason = "Network is unreachable.";
|
||||
}
|
||||
|
||||
resetGlobalSSLparams();
|
||||
|
||||
reply(event->sender(), new EstablishConnectionResponse(this, EventError(errorReason, errorCode),
|
||||
event->connectionType, event->uuid, *repSetInfo.release(),
|
||||
EstablishConnectionResponse::MongoConnection));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- Single server: Connection successful
|
||||
// --- Replica set: Connection successful (primary reachable) or
|
||||
// Connection failed (primary unreachable with at least one reachable member)
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
bool refresh = (ConnectionType::ConnectionRefresh == event->connectionType);
|
||||
ReplicaSet const& setInfo = getReplicaSetInfo(refresh);
|
||||
|
||||
// Check if same set name used with different members which is not supported
|
||||
auto const& members = _connSettings->replicaSetSettings()->members();
|
||||
if (std::find(members.cbegin(), members.cend(), setInfo.primary.toString()) == members.cend())
|
||||
{ // primary not found between user entered members
|
||||
std::string const errorStr = "Different members found under same replica set name \"" +
|
||||
setInfo.setName + "\".";
|
||||
repSetInfo.reset(new ReplicaSet(setInfo));
|
||||
errorCode = EventError::ErrorCode::ServerHasDifferentMembers;
|
||||
LOG_MSG(errorStr, mongo::logger::LogSeverity::Error());
|
||||
throw std::runtime_error(errorStr);
|
||||
}
|
||||
|
||||
if (setInfo.primary.empty()) { // No reachable primary
|
||||
repSetInfo.reset(new ReplicaSet(setInfo)); // Pass possible reachable secondary(ies) info
|
||||
LOG_MSG(setInfo.errorStr, mongo::logger::LogSeverity::Error());
|
||||
throw std::runtime_error(setInfo.errorStr);
|
||||
}
|
||||
else { // Primary is reachable, save setInfo and continue
|
||||
repSetInfo.reset(new ReplicaSet(setInfo));
|
||||
}
|
||||
reply(event->sender(), new EstablishConnectionResponse(this,
|
||||
EventError(errorReason), event->connectionType,
|
||||
EstablishConnectionResponse::MongoConnection));
|
||||
return;
|
||||
}
|
||||
|
||||
if (_connSettings->hasEnabledPrimaryCredential()) {
|
||||
@@ -235,45 +191,44 @@ namespace Robomongo
|
||||
if (dbNames.size() == 0)
|
||||
throw mongo::DBException("Failed to execute \"listdatabases\" command.", 0);
|
||||
|
||||
if (!_connSettings->isReplicaSet())
|
||||
init(); // Init MongoWorker for single server (for replica set connections early init is used)
|
||||
// todo: move to func. getRepSetStatus();
|
||||
mongo::HostAndPort repPrimary;
|
||||
std::vector<bool> repMembersHealths;
|
||||
if (_connSettings->isReplicaSet())
|
||||
{
|
||||
// Refresh view of Replica Set Monitor to get live data
|
||||
auto repSetMonitor = mongo::globalRSMonitorManager.getMonitor(_dbclientRepSet->getSetName());
|
||||
repSetMonitor->startOrContinueRefresh().refreshAll();
|
||||
|
||||
// Update connection settings with primary(master) address and port
|
||||
repPrimary = repSetMonitor->getMasterOrUassert();
|
||||
_connSettings->setServerHost(repPrimary.host());
|
||||
_connSettings->setServerPort(repPrimary.port());
|
||||
|
||||
// Save health of members
|
||||
for (auto const& member : _connSettings->replicaSetSettings()->membersToHostAndPort())
|
||||
{
|
||||
repMembersHealths.push_back(repSetMonitor->isHostUp(member));
|
||||
}
|
||||
}
|
||||
|
||||
// Init MongoWorker
|
||||
init();
|
||||
|
||||
resetGlobalSSLparams();
|
||||
|
||||
auto connInfo = ConnectionInfo(_connSettings->getFullAddress(), dbNames, client->getVersion(),
|
||||
client->getStorageEngineType(), event->uuid);
|
||||
|
||||
// todo: two ctors for rep.set and single server.
|
||||
reply(event->sender(), new EstablishConnectionResponse(this, connInfo, event->connectionType,
|
||||
*repSetInfo.release()));
|
||||
return true;
|
||||
}
|
||||
catch(const std::exception &ex) {
|
||||
reply(event->sender(), new EstablishConnectionResponse(this, ConnectionInfo(_connSettings->getFullAddress(),
|
||||
dbNames, client->getVersion(), client->getStorageEngineType()), event->connectionType, repPrimary, repMembersHealths));
|
||||
} catch(const std::exception &ex) {
|
||||
resetGlobalSSLparams();
|
||||
|
||||
auto errorReason = _connSettings->sslSettings()->sslEnabled() ?
|
||||
EstablishConnectionResponse::ErrorReason::MongoSslConnection :
|
||||
EstablishConnectionResponse::ErrorReason::MongoAuth;
|
||||
EstablishConnectionResponse::ErrorReason::MongoSslConnection :
|
||||
EstablishConnectionResponse::ErrorReason::MongoAuth;
|
||||
|
||||
reply(event->sender(), new EstablishConnectionResponse(this, EventError(ex.what(), errorCode),
|
||||
event->connectionType, ConnectionInfo(event->uuid), *repSetInfo.release(), errorReason));
|
||||
reply(event->sender(),
|
||||
new EstablishConnectionResponse(this, EventError(ex.what()), event->connectionType, errorReason));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MongoWorker::handle(RefreshReplicaSetFolderRequest *event)
|
||||
{
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
|
||||
// Primary is unreachable, but there might be reachable secondary(ies)
|
||||
if (replicaSetInfo.primary.empty()) {
|
||||
reply(event->sender(), new RefreshReplicaSetFolderResponse(this, replicaSetInfo, event->expanded,
|
||||
EventError(replicaSetInfo.errorStr)));
|
||||
LOG_MSG(replicaSetInfo.errorStr, mongo::logger::LogSeverity::Error());
|
||||
return;
|
||||
}
|
||||
else // Primary is reachable
|
||||
reply(event->sender(), new RefreshReplicaSetFolderResponse(this, replicaSetInfo, event->expanded));
|
||||
}
|
||||
|
||||
std::string MongoWorker::getAuthBase() const
|
||||
@@ -351,17 +306,8 @@ namespace Robomongo
|
||||
|
||||
reply(event->sender(), new LoadCollectionNamesResponse(this, event->databaseName(), infos));
|
||||
} catch(const mongo::DBException &ex) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new LoadCollectionNamesResponse(this,
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false)));
|
||||
}
|
||||
else // other errors
|
||||
reply(event->sender(), new LoadCollectionNamesResponse(this, EventError(ex.what())));
|
||||
}
|
||||
else // single server
|
||||
reply(event->sender(), new LoadCollectionNamesResponse(this, EventError(ex.what())));
|
||||
reply(event->sender(), new LoadCollectionNamesResponse(this, EventError(ex.what())));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,17 +320,8 @@ namespace Robomongo
|
||||
|
||||
reply(event->sender(), new LoadUsersResponse(this, event->databaseName(), users));
|
||||
} catch(const mongo::DBException &ex) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new LoadUsersResponse(this,
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false)));
|
||||
}
|
||||
else // other errors
|
||||
reply(event->sender(), new LoadUsersResponse(this, EventError(ex.what())));
|
||||
}
|
||||
else // single server
|
||||
reply(event->sender(), new LoadUsersResponse(this, EventError(ex.what())));
|
||||
reply(event->sender(), new LoadUsersResponse(this, EventError(ex.what())));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,17 +393,8 @@ namespace Robomongo
|
||||
|
||||
reply(event->sender(), new LoadFunctionsResponse(this, event->databaseName(), funs));
|
||||
} catch(const mongo::DBException &ex) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new LoadFunctionsResponse(this,
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false)));
|
||||
}
|
||||
else // other errors
|
||||
reply(event->sender(), new LoadFunctionsResponse(this, EventError(ex.what())));
|
||||
}
|
||||
else // single server
|
||||
reply(event->sender(), new LoadFunctionsResponse(this, EventError(ex.what())));
|
||||
reply(event->sender(), new LoadFunctionsResponse(this, EventError(ex.what())));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,22 +409,12 @@ namespace Robomongo
|
||||
client->insertDocument(event->obj(), event->ns());
|
||||
|
||||
client->done();
|
||||
|
||||
reply(event->sender(), new InsertDocumentResponse(this));
|
||||
}
|
||||
catch(const mongo::DBException &ex) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new InsertDocumentResponse(this,
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false)));
|
||||
}
|
||||
else // other errors
|
||||
reply(event->sender(), new InsertDocumentResponse(this, EventError(ex.toString())));
|
||||
}
|
||||
else { // single server
|
||||
reply(event->sender(), new InsertDocumentResponse(this,
|
||||
EventError("Error when saving document: " + ex.toString())));
|
||||
}
|
||||
} catch(const mongo::DBException &ex) {
|
||||
EventError error = EventError("Error when saving document: " + ex.toString());
|
||||
reply(event->sender(), new InsertDocumentResponse(this, error));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,25 +423,14 @@ namespace Robomongo
|
||||
try {
|
||||
boost::scoped_ptr<MongoClient> client(getClient());
|
||||
|
||||
client->removeDocuments(event->ns(), event->query(), (event->removeCount() == RemoveDocumentCount::ONE));
|
||||
client->removeDocuments(event->ns(), event->query(), event->justOne());
|
||||
client->done();
|
||||
|
||||
reply(event->sender(), new RemoveDocumentResponse(this, event->removeCount(), event->index()));
|
||||
}
|
||||
catch(const mongo::DBException &ex) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new RemoveDocumentResponse(this,
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false), event->removeCount(), event->index()));
|
||||
}
|
||||
else // other errors
|
||||
reply(event->sender(), new RemoveDocumentResponse(this, EventError(ex.what()),
|
||||
event->removeCount(), event->index()));
|
||||
}
|
||||
else // single server
|
||||
reply(event->sender(), new RemoveDocumentResponse(this,
|
||||
EventError("Error when deleting document: " + ex.toString()), event->removeCount(), event->index()));
|
||||
reply(event->sender(), new RemoveDocumentResponse(this));
|
||||
} catch(const mongo::DBException &ex) {
|
||||
EventError error = EventError("Error when deleting document: " + ex.toString());
|
||||
reply(event->sender(), new RemoveDocumentResponse(this, error));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,49 +459,11 @@ namespace Robomongo
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to handle case where new shell (which was opened when server unreachable) was re-executed
|
||||
if (_scriptEngine->failedScope()) {
|
||||
try {
|
||||
_scriptEngine->init(_isLoadMongoRcJs);
|
||||
}
|
||||
catch (std::exception const& ex) {
|
||||
LOG_MSG(captilizeFirstChar(ex.what()) + ", cannot init mongo scope",
|
||||
mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
// todo: should we use dbName from event or _connSettings?
|
||||
MongoShellExecResult result = _scriptEngine->exec(event->script, _connSettings->defaultDatabase());
|
||||
// To fix the problem where 'result' comes with old primary address.
|
||||
if (_connSettings->isReplicaSet())
|
||||
result.setCurrentServer(_dbclientRepSet->getSuspectedPrimaryHostAndPort().toString());
|
||||
|
||||
|
||||
if (result.error()) {
|
||||
// If this is replica set, update script engine and try again
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new ExecuteScriptResponse(this,
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false)));
|
||||
return;
|
||||
}
|
||||
else { // primary reachable
|
||||
_scriptEngine->init(_isLoadMongoRcJs, replicaSetInfo.primary.toString(),
|
||||
_connSettings->defaultDatabase());
|
||||
result = _scriptEngine->exec(event->script, _connSettings->defaultDatabase());
|
||||
}
|
||||
}
|
||||
else { // single server
|
||||
reply(event->sender(), new ExecuteScriptResponse(this, EventError(result.errorMessage())));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MongoShellExecResult result = _scriptEngine->exec(event->script, event->databaseName);
|
||||
reply(event->sender(), new ExecuteScriptResponse(this, result, event->script.empty()));
|
||||
}
|
||||
catch(const std::exception &ex) {
|
||||
reply(event->sender(), new ExecuteScriptResponse(this, EventError(ex.what(), EventError::Unknown, false)));
|
||||
} catch(const mongo::DBException &ex) {
|
||||
reply(event->sender(), new ExecuteScriptResponse(this, EventError(ex.what())));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -636,23 +505,14 @@ namespace Robomongo
|
||||
boost::scoped_ptr<MongoClient> client(getClient());
|
||||
client->createDatabase(event->database());
|
||||
|
||||
// Insert to list of created database. Read docs for this hashset in the header
|
||||
// Insert to list of created database
|
||||
// Read docs for this hashset in the header
|
||||
_createdDbs.insert(event->database());
|
||||
|
||||
reply(event->sender(), new CreateDatabaseResponse(this, event->database()));
|
||||
reply(event->sender(), new CreateDatabaseResponse(this));
|
||||
} catch(const mongo::DBException &ex) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new CreateDatabaseResponse(this, event->database(),
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false)));
|
||||
}
|
||||
else // other errors
|
||||
reply(event->sender(), new CreateDatabaseResponse(this, event->database(),
|
||||
EventError(ex.toString())));
|
||||
}
|
||||
else // single server
|
||||
reply(event->sender(), new CreateDatabaseResponse(this, event->database(), EventError(ex.what())));
|
||||
reply(event->sender(), new CreateDatabaseResponse(this, EventError(ex.what())));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -660,76 +520,45 @@ namespace Robomongo
|
||||
{
|
||||
try {
|
||||
boost::scoped_ptr<MongoClient> client(getClient());
|
||||
client->dropDatabase(event->database);
|
||||
client->dropDatabase(event->database());
|
||||
|
||||
// Remove from the list of created database, Read docs for this hashset in the header
|
||||
_createdDbs.erase(event->database);
|
||||
// Remove from the list of created database
|
||||
// Read docs for this hashset in the header
|
||||
_createdDbs.erase(event->database());
|
||||
|
||||
reply(event->sender(), new DropDatabaseResponse(this, event->database));
|
||||
}
|
||||
catch(const mongo::DBException &ex) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new DropDatabaseResponse(this, event->database,
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false)));
|
||||
}
|
||||
else // other errors
|
||||
reply(event->sender(), new DropDatabaseResponse(this, event->database, EventError(ex.toString())));
|
||||
}
|
||||
else // single server
|
||||
reply(event->sender(), new DropDatabaseResponse(this, event->database, EventError(ex.what())));
|
||||
reply(event->sender(), new DropDatabaseResponse(this));
|
||||
} catch(const mongo::DBException &ex) {
|
||||
reply(event->sender(), new DropDatabaseResponse(this, EventError(ex.what())));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
void MongoWorker::handle(CreateCollectionRequest *event)
|
||||
{
|
||||
std::string const& collection = event->ns().collectionName();
|
||||
|
||||
try {
|
||||
boost::scoped_ptr<MongoClient> client(getClient());
|
||||
client->createCollection(event->ns().toString(), event->getSize(), event->getCapped(),
|
||||
client->createCollection(event->getNs().toString(), event->getSize(), event->getCapped(),
|
||||
event->getMaxDocNum(), event->getExtraOptions());
|
||||
client->done();
|
||||
|
||||
reply(event->sender(), new CreateCollectionResponse(this, collection));
|
||||
reply(event->sender(), new CreateCollectionResponse(this));
|
||||
} catch(const mongo::DBException &ex) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new CreateCollectionResponse(this, collection,
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false)));
|
||||
}
|
||||
else // other errors
|
||||
reply(event->sender(), new CreateCollectionResponse(this, collection, EventError(ex.toString())));
|
||||
}
|
||||
else // single server
|
||||
reply(event->sender(), new CreateCollectionResponse(this, collection, EventError(ex.what())));
|
||||
reply(event->sender(), new CreateCollectionResponse(this, EventError(ex.what())));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
void MongoWorker::handle(DropCollectionRequest *event)
|
||||
{
|
||||
std::string const& collection = event->ns().collectionName();
|
||||
|
||||
try {
|
||||
boost::scoped_ptr<MongoClient> client(getClient());
|
||||
client->dropCollection(event->ns());
|
||||
client->done();
|
||||
|
||||
reply(event->sender(), new DropCollectionResponse(this, collection));
|
||||
reply(event->sender(), new DropCollectionResponse(this));
|
||||
} catch(const mongo::DBException &ex) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new DropCollectionResponse(this, collection,
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false)));
|
||||
}
|
||||
else // other errors
|
||||
reply(event->sender(), new DropCollectionResponse(this, collection, EventError(ex.toString())));
|
||||
}
|
||||
else // single server
|
||||
reply(event->sender(), new DropCollectionResponse(this, collection, EventError(ex.what())));
|
||||
reply(event->sender(), new DropCollectionResponse(this, EventError(ex.what())));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -740,46 +569,24 @@ namespace Robomongo
|
||||
client->renameCollection(event->ns(), event->newCollection());
|
||||
client->done();
|
||||
|
||||
reply(event->sender(), new RenameCollectionResponse(this, event->ns().collectionName(),
|
||||
event->newCollection()));
|
||||
reply(event->sender(), new RenameCollectionResponse(this));
|
||||
} catch(const mongo::DBException &ex) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new RenameCollectionResponse(this,
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false)));
|
||||
}
|
||||
else // other errors
|
||||
reply(event->sender(), new RenameCollectionResponse(this, EventError(ex.toString())));
|
||||
}
|
||||
else // single server
|
||||
reply(event->sender(), new RenameCollectionResponse(this, EventError(ex.what())));
|
||||
reply(event->sender(), new RenameCollectionResponse(this, EventError(ex.what())));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
void MongoWorker::handle(DuplicateCollectionRequest *event)
|
||||
{
|
||||
std::string const& sourceCollection = event->ns().collectionName();
|
||||
|
||||
try {
|
||||
boost::scoped_ptr<MongoClient> client(getClient());
|
||||
client->duplicateCollection(event->ns(), event->newCollection());
|
||||
client->done();
|
||||
|
||||
reply(event->sender(), new DuplicateCollectionResponse(this, sourceCollection, event->newCollection()));
|
||||
}
|
||||
catch (const mongo::DBException &ex) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new DuplicateCollectionResponse(this, sourceCollection,
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false)));
|
||||
}
|
||||
else // other errors
|
||||
reply(event->sender(), new DuplicateCollectionResponse(this, sourceCollection, EventError(ex.what())));
|
||||
}
|
||||
else // single server
|
||||
reply(event->sender(), new DuplicateCollectionResponse(this, sourceCollection, EventError(ex.what())));
|
||||
reply(event->sender(), new DuplicateCollectionResponse(this));
|
||||
} catch(const mongo::DBException &ex) {
|
||||
reply(event->sender(), new DuplicateCollectionResponse(this, EventError(ex.what())));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -805,21 +612,10 @@ namespace Robomongo
|
||||
client->createUser(event->database(), event->user(), event->overwrite());
|
||||
client->done();
|
||||
|
||||
reply(event->sender(), new CreateUserResponse(this, event->user().name()));
|
||||
reply(event->sender(), new CreateUserResponse(this));
|
||||
} catch(const mongo::DBException &ex) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new CreateUserResponse(this, event->user().name(),
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false)));
|
||||
}
|
||||
else // other errors
|
||||
reply(event->sender(), new CreateUserResponse(this, event->user().name(),
|
||||
EventError(ex.what())));
|
||||
}
|
||||
else // single server
|
||||
reply(event->sender(), new CreateUserResponse(this, event->user().name(),
|
||||
EventError(ex.what())));
|
||||
reply(event->sender(), new CreateUserResponse(this, EventError(ex.what())));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -830,44 +626,24 @@ namespace Robomongo
|
||||
client->dropUser(event->database(), event->id());
|
||||
client->done();
|
||||
|
||||
reply(event->sender(), new DropUserResponse(this, event->username()));
|
||||
reply(event->sender(), new DropUserResponse(this));
|
||||
} catch(const mongo::DBException &ex) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new DropUserResponse(this, event->username(),
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false)));
|
||||
}
|
||||
else // other errors
|
||||
reply(event->sender(), new DropUserResponse(this, event->username(), EventError(ex.what())));
|
||||
}
|
||||
else // single server
|
||||
reply(event->sender(), new DropUserResponse(this, event->username(), EventError(ex.what())));
|
||||
reply(event->sender(), new DropUserResponse(this, EventError(ex.what())));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
void MongoWorker::handle(CreateFunctionRequest *event)
|
||||
{
|
||||
std::string const& functionName = event->function().name();
|
||||
|
||||
try {
|
||||
boost::scoped_ptr<MongoClient> client(getClient());
|
||||
client->createFunction(event->database(), event->function(), event->existingFunctionName());
|
||||
client->done();
|
||||
|
||||
reply(event->sender(), new CreateFunctionResponse(this, functionName));
|
||||
reply(event->sender(), new CreateFunctionResponse(this));
|
||||
} catch(const mongo::DBException &ex) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new CreateFunctionResponse(this, functionName,
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false)));
|
||||
}
|
||||
else // other errors
|
||||
reply(event->sender(), new CreateFunctionResponse(this, functionName, EventError(ex.what())));
|
||||
}
|
||||
else // single server
|
||||
reply(event->sender(), new CreateFunctionResponse(this, functionName, EventError(ex.what())));
|
||||
reply(event->sender(), new CreateFunctionResponse(this, EventError(ex.what())));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -875,52 +651,42 @@ namespace Robomongo
|
||||
{
|
||||
try {
|
||||
boost::scoped_ptr<MongoClient> client(getClient());
|
||||
client->dropFunction(event->database(), event->functionName());
|
||||
client->dropFunction(event->database(), event->name());
|
||||
client->done();
|
||||
|
||||
reply(event->sender(), new DropFunctionResponse(this, event->functionName()));
|
||||
}
|
||||
catch (const mongo::DBException &ex) {
|
||||
if (_connSettings->isReplicaSet()) {
|
||||
ReplicaSet const& replicaSetInfo = getReplicaSetInfo(true);
|
||||
if (replicaSetInfo.primary.empty()) { // primary not reachable
|
||||
reply(event->sender(), new DropFunctionResponse(this, event->functionName(),
|
||||
EventError(PRIMARY_UNREACHABLE, replicaSetInfo, false)));
|
||||
}
|
||||
else // other errors
|
||||
reply(event->sender(), new DropFunctionResponse(this, event->functionName(), EventError(ex.what())));
|
||||
}
|
||||
else // single server
|
||||
reply(event->sender(), new DropFunctionResponse(this, event->functionName(), EventError(ex.what())));
|
||||
reply(event->sender(), new DropFunctionResponse(this));
|
||||
} catch(const mongo::DBException &ex) {
|
||||
reply(event->sender(), new DropFunctionResponse(this, EventError(ex.what())));
|
||||
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
|
||||
}
|
||||
}
|
||||
|
||||
mongo::DBClientBase *MongoWorker::getConnection(bool mayReturnNull /* = false */)
|
||||
{
|
||||
configureSSL();
|
||||
// --- Configure SSL first --- Todo: move to function?
|
||||
// As a precaution reset SSL global params for any kind of connection request (SSL or non-SSL)
|
||||
resetGlobalSSLparams();
|
||||
|
||||
// Update global mongo SSL settings according to SSL enable/disabled status
|
||||
if (_connSettings->sslSettings()->sslEnabled())
|
||||
{
|
||||
// Force SSL mode for outgoing connections
|
||||
mongo::sslGlobalParams.sslMode.store(mongo::SSLParams::SSLMode_requireSSL);
|
||||
updateGlobalSSLparams();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disable forced SSL mode for outgoing connections
|
||||
mongo::sslGlobalParams.sslMode.store(mongo::SSLParams::SSLMode_allowSSL);
|
||||
}
|
||||
|
||||
// --- Perform connection ---
|
||||
if (_connSettings->isReplicaSet()) // connection to replica set
|
||||
{
|
||||
if (!_dbclientRepSet)
|
||||
{
|
||||
init(); // Init mongoworker for early-use of _scriptEngine
|
||||
if (_connSettings->isReplicaSet()) { // connection to replica set
|
||||
if (!_dbclientRepSet) {
|
||||
_dbclientRepSet = std::unique_ptr<mongo::DBClientReplicaSet>(
|
||||
// todo: where to get name of replica? (i.e. repset) - todo: this if causes crash after app close
|
||||
new mongo::DBClientReplicaSet("repset",_connSettings->replicaSetSettings()->membersToHostAndPort(), _mongoTimeoutSec));
|
||||
|
||||
// Step-1: Use user entered set name or retrieve set name from cache or from a reachable member
|
||||
std::string setName = _connSettings->replicaSetSettings()->setNameUserEntered();
|
||||
if (setName.empty()) {
|
||||
setName = _connSettings->replicaSetSettings()->cachedSetName();
|
||||
if (setName.empty()) // If there is no cached set name, get it from an on-line replica node
|
||||
setName = connectAndGetReplicaSetName();
|
||||
|
||||
if (setName.empty()) // It is not possible to continue with empty set name
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Step-2: Try connect to replica set with set name
|
||||
auto const& membersHostsAndPorts = _connSettings->replicaSetSettings()->membersToHostAndPort();
|
||||
_dbclientRepSet = DBClientReplicaSet(new mongo::DBClientReplicaSet(setName, membersHostsAndPorts,
|
||||
_mongoTimeoutSec));
|
||||
bool const connStatus = _dbclientRepSet->connect();
|
||||
|
||||
if (!connStatus) {
|
||||
@@ -929,15 +695,17 @@ namespace Robomongo
|
||||
}
|
||||
return _dbclientRepSet.get();
|
||||
}
|
||||
else { // connection to single server
|
||||
else { // connection to single server
|
||||
if (!_dbclient) {
|
||||
// Timeout for operations
|
||||
// Connect timeout is fixed, but short, at 5 seconds (see headers for DBClientConnection)
|
||||
_dbclient = DBClientConnection(new mongo::DBClientConnection(true, _mongoTimeoutSec));
|
||||
_dbclient = std::unique_ptr<mongo::DBClientConnection>(new mongo::DBClientConnection(true, _mongoTimeoutSec));
|
||||
|
||||
mongo::Status status = _dbclient->connect(_connSettings->hostAndPort());
|
||||
if (!status.isOK() && mayReturnNull)
|
||||
mongo::Status status = _dbclient->connect(_connSettings->info());
|
||||
|
||||
if (!status.isOK() && mayReturnNull) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return _dbclient.get();
|
||||
}
|
||||
@@ -948,22 +716,6 @@ namespace Robomongo
|
||||
return new MongoClient(getConnection());
|
||||
}
|
||||
|
||||
void MongoWorker::configureSSL()
|
||||
{
|
||||
// As a precaution reset SSL global params for any kind of connection request (SSL or non-SSL)
|
||||
resetGlobalSSLparams();
|
||||
// Update global SSL mode and global mongo SSL settings
|
||||
if (_connSettings->sslSettings()->sslEnabled()) {
|
||||
// Force SSL mode for outgoing connections
|
||||
mongo::sslGlobalParams.sslMode.store(mongo::SSLParams::SSLMode_requireSSL);
|
||||
updateGlobalSSLparams();
|
||||
}
|
||||
else {
|
||||
// Disable forced SSL mode for outgoing connections
|
||||
mongo::sslGlobalParams.sslMode.store(mongo::SSLParams::SSLMode_allowSSL);
|
||||
}
|
||||
}
|
||||
|
||||
void MongoWorker::updateGlobalSSLparams() const
|
||||
{
|
||||
resetGlobalSSLparams();
|
||||
@@ -995,82 +747,6 @@ namespace Robomongo
|
||||
mongo::sslGlobalParams.sslAllowInvalidHostnames = false;
|
||||
}
|
||||
|
||||
ReplicaSet MongoWorker::getReplicaSetInfo(bool refresh /*= true*/) const
|
||||
{
|
||||
std::string setName;
|
||||
mongo::HostAndPort primary;
|
||||
std::vector<std::pair<std::string, bool>> membersAndHealths;
|
||||
|
||||
// Refresh view of Replica Set Monitor to get live data
|
||||
auto repSetMonitor = mongo::globalRSMonitorManager.getMonitor(_dbclientRepSet->getSetName());
|
||||
|
||||
// Handle long lasting (e.g. overnight) connections which causes replica set monitor to be null
|
||||
if (!repSetMonitor) {
|
||||
mongo::ReplicaSetMonitor::createIfNeeded(_dbclientRepSet->getSetName(),
|
||||
_connSettings->replicaSetSettings()->membersToHostAndPortAsSet());
|
||||
repSetMonitor = mongo::globalRSMonitorManager.getMonitor(_dbclientRepSet->getSetName());
|
||||
if (!repSetMonitor) // if nullptr again even if the set is reachable, something went really wrong.
|
||||
return ReplicaSet(setName, primary, membersAndHealths,
|
||||
"Unexpected error. Unable to get replica set monitor for set name: " +
|
||||
_dbclientRepSet->getSetName() + "\nPlease open a new connection.");
|
||||
}
|
||||
|
||||
// refreshAll() takes long time, in order to do first establish connection request much faster
|
||||
// refreshAll() will be by-passed first and it will/must be done after a successful connection.
|
||||
if (refresh)
|
||||
repSetMonitor->startOrContinueRefresh().refreshAll();
|
||||
|
||||
setName = repSetMonitor->getName();
|
||||
auto const primaryOnly = mongo::ReadPreferenceSetting(mongo::ReadPreference::PrimaryOnly, mongo::TagSet());
|
||||
auto primaryWithStatus = repSetMonitor->getHostOrRefresh(primaryOnly, mongo::Milliseconds(2000)); // todo
|
||||
if (primaryWithStatus.isOK())
|
||||
primary = primaryWithStatus.getValue();
|
||||
|
||||
QStringList servers;
|
||||
// i.e. setNameAndMembers: "repset/localhost:27017,localhost:27018,localhost:27019"
|
||||
auto setNameAndMembers = QString::fromStdString(repSetMonitor->getServerAddress());
|
||||
QStringList result = setNameAndMembers.split("/");
|
||||
if (result.size() > 1)
|
||||
servers = result[1].split(",");
|
||||
|
||||
// Save address and health of replica members
|
||||
for (QString const& server : servers) {
|
||||
auto hostAndPort = mongo::HostAndPort(mongo::StringData(server.toStdString()));
|
||||
membersAndHealths.push_back({ server.toStdString(), repSetMonitor->isHostUp(hostAndPort) });
|
||||
}
|
||||
|
||||
return ReplicaSet(setName, primary, membersAndHealths, primaryWithStatus.getStatus().reason());
|
||||
}
|
||||
|
||||
std::string MongoWorker::connectAndGetReplicaSetName() const
|
||||
{
|
||||
auto dbclientTemp = DBClientConnection(new mongo::DBClientConnection(true, 10));
|
||||
std::string setName = "";
|
||||
|
||||
// Try connecting to the nodes one by one until getting replica set name.
|
||||
for (auto const& node : _connSettings->replicaSetSettings()->membersToHostAndPort())
|
||||
{
|
||||
mongo::Status const status = dbclientTemp->connect(node);
|
||||
if (status.isOK())
|
||||
{
|
||||
_scriptEngine->init(_isLoadMongoRcJs, node.toString());
|
||||
MongoShellExecResult result = _scriptEngine->exec("rs.status()", "");
|
||||
if (!result.results().empty())
|
||||
{
|
||||
auto resultDocs = result.results().front().documents();
|
||||
if (!resultDocs.empty())
|
||||
{
|
||||
setName = resultDocs.front()->bsonObj().getStringField("set");
|
||||
if (!setName.empty()) // We get the information, finish the loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return setName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send event to this MongoWorker
|
||||
*/
|
||||
@@ -1092,19 +768,4 @@ namespace Robomongo
|
||||
|
||||
AppRegistry::instance().bus()->send(receiver, event);
|
||||
}
|
||||
|
||||
void MongoWorker::pingDatabase(mongo::DBClientBase *dbclient) const
|
||||
{
|
||||
// Building { ping: 1 }
|
||||
mongo::BSONObjBuilder command;
|
||||
command.append("ping", 1);
|
||||
mongo::BSONObj result;
|
||||
std::string authBase = getAuthBase();
|
||||
if (authBase.empty()) {
|
||||
dbclient->runCommand("admin", command.obj(), result);
|
||||
}
|
||||
else {
|
||||
dbclient->runCommand(authBase, command.obj(), result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <QMutex>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <mongo/client/dbclient_rs.h>
|
||||
#include <mongo/client/dbclient_rs.h> // todo: move
|
||||
|
||||
#include "robomongo/core/events/MongoEvents.h"
|
||||
|
||||
@@ -24,23 +24,16 @@ namespace Robomongo
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum { pingTimeMs = 60 * 1000 };
|
||||
|
||||
typedef std::vector<std::string> DatabasesContainerType;
|
||||
using DBClientReplicaSet = std::unique_ptr<mongo::DBClientReplicaSet>;
|
||||
using DBClientConnection = std::unique_ptr<mongo::DBClientConnection>;
|
||||
|
||||
explicit MongoWorker(ConnectionSettings *connection, bool isLoadMongoRcJs, int batchSize,
|
||||
int mongoTimeoutSec, int shellTimeoutSec, QObject *parent = NULL);
|
||||
|
||||
~MongoWorker();
|
||||
enum { pingTimeMs = 60 * 1000 };
|
||||
void interrupt();
|
||||
void stopAndDelete();
|
||||
|
||||
protected Q_SLOTS:
|
||||
|
||||
protected Q_SLOTS: // handlers:
|
||||
void init();
|
||||
|
||||
/**
|
||||
* @brief Every minute we are issuing { ping : 1 } command to every used connection
|
||||
* in order to avoid dropped connections.
|
||||
@@ -50,13 +43,7 @@ namespace Robomongo
|
||||
/**
|
||||
* @brief Initiate connection to MongoDB
|
||||
*/
|
||||
bool handle(EstablishConnectionRequest *event);
|
||||
|
||||
/**
|
||||
* @brief Try to re-connect to MongoDB replica set in order to refresh connection view.
|
||||
* For more details, see MongoServer::tryRefreshReplicaSetFolder()
|
||||
*/
|
||||
void handle(RefreshReplicaSetFolderRequest *event);
|
||||
void handle(EstablishConnectionRequest *event);
|
||||
|
||||
/**
|
||||
* @brief Load list of all database names
|
||||
@@ -143,18 +130,14 @@ namespace Robomongo
|
||||
* @brief Send event to this MongoWorker
|
||||
*/
|
||||
void send(Event *event);
|
||||
|
||||
DatabasesContainerType getDatabaseNamesSafe();
|
||||
std::string getAuthBase() const;
|
||||
|
||||
std::unique_ptr<mongo::DBClientConnection> _dbclient;
|
||||
std::unique_ptr<mongo::DBClientReplicaSet> _dbclientRepSet;
|
||||
mongo::DBClientBase *getConnection(bool mayReturnNull = false);
|
||||
MongoClient *getClient();
|
||||
|
||||
/**
|
||||
*@brief Reset and update global mongo SSL settings (mongo::sslGlobalParams)
|
||||
*/
|
||||
void configureSSL();
|
||||
|
||||
/**
|
||||
*@brief Update global mongo SSL settings (mongo::sslGlobalParams) according to active connection
|
||||
* request's SSL settings.
|
||||
@@ -166,34 +149,14 @@ namespace Robomongo
|
||||
*/
|
||||
void resetGlobalSSLparams() const;
|
||||
|
||||
/**
|
||||
*@brief Update Replica Set related parameters/settings.
|
||||
* Warning: Using parameter 'refresh' as false might return incorrect cached values for status
|
||||
* of secondary members.
|
||||
* @param refresh : If true it will be deep scan of replica set status which
|
||||
* might take quite some time. If false, it will be quick scan
|
||||
* which might return incorrect cached values for status of secondary members.
|
||||
* Use false only to achieve quick first connection, in all other cases true
|
||||
* should be used.
|
||||
*/
|
||||
ReplicaSet getReplicaSetInfo(bool refresh = true) const;
|
||||
|
||||
std::string connectAndGetReplicaSetName() const;
|
||||
|
||||
/**
|
||||
* @brief Send reply event to object 'obj'
|
||||
*/
|
||||
void reply(QObject *receiver, Event *event);
|
||||
|
||||
/**
|
||||
* @brief Send hear beat messages to database in order to keep connection alive
|
||||
*/
|
||||
void pingDatabase(mongo::DBClientBase *dbclient) const;
|
||||
|
||||
QThread *_thread;
|
||||
QMutex _firstConnectionMutex;
|
||||
|
||||
std::unique_ptr<ScriptEngine> _scriptEngine;
|
||||
ScriptEngine *_scriptEngine;
|
||||
|
||||
bool _isAdmin;
|
||||
const bool _isLoadMongoRcJs;
|
||||
@@ -204,9 +167,6 @@ namespace Robomongo
|
||||
int _shellTimeoutSec;
|
||||
QAtomicInteger<int> _isQuiting;
|
||||
|
||||
std::unique_ptr<mongo::DBClientConnection> _dbclient;
|
||||
std::unique_ptr<mongo::DBClientReplicaSet> _dbclientRepSet;
|
||||
|
||||
ConnectionSettings *_connSettings;
|
||||
|
||||
// Collection of created databases.
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
#include "robomongo/core/mongodb/ReplicaSet.h"
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
ReplicaSet::ReplicaSet(std::string const& setName, const mongo::HostAndPort primary,
|
||||
std::vector<std::pair<std::string, bool>> const& membersAndHealths,
|
||||
std::string const& errorStr)
|
||||
: setName(setName), primary(primary), membersAndHealths(membersAndHealths),
|
||||
errorStr(errorStr)
|
||||
{}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <mongo/util/net/hostandport.h>
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
/**
|
||||
* @brief Struct to represent live information of a replica set.
|
||||
*/
|
||||
struct ReplicaSet
|
||||
{
|
||||
ReplicaSet(std::string const& setName, const mongo::HostAndPort primary,
|
||||
std::vector<std::pair<std::string, bool>> const& membersAndHealths, std::string const& errorStr = "");
|
||||
|
||||
ReplicaSet() {};
|
||||
|
||||
std::string const setName;
|
||||
mongo::HostAndPort const primary;
|
||||
std::vector<std::pair<std::string, bool>> const membersAndHealths; // pair: {HostNameAndPort, Health}
|
||||
std::string const errorStr;
|
||||
};
|
||||
}
|
||||
@@ -2,16 +2,12 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <QUuid>
|
||||
|
||||
#include "robomongo/core/settings/CredentialSettings.h"
|
||||
#include "robomongo/core/settings/ReplicaSetSettings.h"
|
||||
#include "robomongo/core/settings/SshSettings.h"
|
||||
#include "robomongo/core/settings/SslSettings.h"
|
||||
#include "robomongo/core/utils/QtUtils.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
const unsigned port = 27017;
|
||||
@@ -23,54 +19,21 @@ namespace
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
|
||||
/**
|
||||
* Creates ConnectionSettings with default values
|
||||
*/
|
||||
ConnectionSettings::ConnectionSettings(bool isClone) : QObject(),
|
||||
ConnectionSettings::ConnectionSettings() : QObject(),
|
||||
_connectionName(defaultNameConnection),
|
||||
_host(defaultServerHost),
|
||||
_port(port),
|
||||
_imported(false),
|
||||
_sshSettings(new SshSettings()),
|
||||
_sslSettings(new SslSettings()),
|
||||
_isReplicaSet(false),
|
||||
_replicaSetSettings(new ReplicaSetSettings()),
|
||||
_clone(isClone)
|
||||
_isReplicaSet(false)
|
||||
{ }
|
||||
|
||||
ConnectionSettings::ConnectionSettings(const mongo::MongoURI& uri, bool isClone)
|
||||
: _connectionName(defaultNameConnection),
|
||||
_host(defaultServerHost),
|
||||
_port(port),
|
||||
_imported(false),
|
||||
_sshSettings(new SshSettings()),
|
||||
_sslSettings(new SslSettings()),
|
||||
_isReplicaSet((uri.type() == mongo::ConnectionString::ConnectionType::SET)),
|
||||
_replicaSetSettings(new ReplicaSetSettings(uri)),
|
||||
_clone(isClone)
|
||||
{
|
||||
if (!uri.getServers().empty()) {
|
||||
_host = uri.getServers().front().host();
|
||||
_port = uri.getServers().front().port();
|
||||
}
|
||||
|
||||
auto str = std::string(uri.getOptions().getStringField("ssl"));
|
||||
auto sslEnabled = ("true" == str);
|
||||
if (sslEnabled) {
|
||||
_sslSettings->enableSSL(true);
|
||||
_sslSettings->setAllowInvalidCertificates(true);
|
||||
}
|
||||
|
||||
auto credential = new CredentialSettings();
|
||||
credential->setUserName(uri.getUser());
|
||||
credential->setUserPassword(uri.getPassword());
|
||||
credential->setDatabaseName(uri.getDatabase());
|
||||
if (!credential->userName().empty() && !credential->userPassword().empty()) { // todo:
|
||||
credential->setEnabled(true);
|
||||
}
|
||||
addCredential(credential);
|
||||
}
|
||||
|
||||
void ConnectionSettings::fromVariant(const QVariantMap &map) {
|
||||
setConnectionName(QtUtils::toStdString(map.value("connectionName").toString()));
|
||||
setServerHost(QtUtils::toStdString(map.value("serverHost").toString().left(maxLength)));
|
||||
@@ -97,13 +60,6 @@ namespace Robomongo
|
||||
_replicaSetSettings->fromVariant(map.value("replicaSet").toMap());
|
||||
}
|
||||
|
||||
// If UUID has never been created or is empty, create a new one. Otherwise load the existing.
|
||||
if (!map.contains("uuid") || map.value("uuid").toString().isEmpty())
|
||||
_uuid = QUuid::createUuid().toString();
|
||||
else
|
||||
_uuid = map.value("uuid").toString();
|
||||
|
||||
|
||||
//#ifdef MONGO_SSL
|
||||
// ,SSLInfo(map.value("sslEnabled").toBool(),QtUtils::toStdString(map.value("sslPemKeyFile").toString()))
|
||||
//#endif
|
||||
@@ -115,6 +71,9 @@ namespace Robomongo
|
||||
ConnectionSettings::~ConnectionSettings()
|
||||
{
|
||||
clearCredentials();
|
||||
delete _sshSettings;
|
||||
delete _sslSettings;
|
||||
delete _replicaSetSettings; // todo: unique_ptr
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,10 +81,9 @@ namespace Robomongo
|
||||
*/
|
||||
ConnectionSettings *ConnectionSettings::clone() const
|
||||
{
|
||||
auto settings = new ConnectionSettings(true);
|
||||
settings->setUuid(_uuid);
|
||||
settings->apply(this);
|
||||
return settings;
|
||||
ConnectionSettings *record = new ConnectionSettings();
|
||||
record->apply(this);
|
||||
return record;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,9 +104,9 @@ namespace Robomongo
|
||||
addCredential((*it)->clone());
|
||||
}
|
||||
|
||||
_sshSettings.reset(source->sshSettings()->clone());
|
||||
_sslSettings.reset(source->sslSettings()->clone());
|
||||
_replicaSetSettings.reset(source->_replicaSetSettings->clone());
|
||||
_sshSettings = source->sshSettings()->clone();
|
||||
_sslSettings = source->sslSettings()->clone();
|
||||
_replicaSetSettings = source->_replicaSetSettings->clone(); // todo: leak candidate
|
||||
|
||||
//#ifdef MONGO_SSL
|
||||
// setSslInfo(source->sslInfo());
|
||||
@@ -184,14 +142,13 @@ namespace Robomongo
|
||||
|
||||
map.insert("ssh", _sshSettings->toVariant());
|
||||
map.insert("ssl", _sslSettings->toVariant());
|
||||
map.insert("uuid", _uuid);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
CredentialSettings *ConnectionSettings::findCredential(const std::string &databaseName) const
|
||||
{
|
||||
CredentialSettings *result = nullptr;
|
||||
CredentialSettings *result = NULL;
|
||||
for (QList<CredentialSettings *>::const_iterator it = _credentials.begin(); it != _credentials.end(); ++it) {
|
||||
CredentialSettings *cred = *it;
|
||||
if (cred->databaseName() == databaseName) {
|
||||
@@ -215,7 +172,7 @@ namespace Robomongo
|
||||
* @brief Checks whether this connection has primary credential
|
||||
* which is also enabled.
|
||||
*/
|
||||
bool ConnectionSettings::hasEnabledPrimaryCredential() const
|
||||
bool ConnectionSettings::hasEnabledPrimaryCredential()
|
||||
{
|
||||
if (_credentials.count() == 0)
|
||||
return false;
|
||||
@@ -226,7 +183,7 @@ namespace Robomongo
|
||||
/**
|
||||
* @brief Returns primary credential
|
||||
*/
|
||||
CredentialSettings *ConnectionSettings::primaryCredential() const
|
||||
CredentialSettings *ConnectionSettings::primaryCredential()
|
||||
{
|
||||
if (_credentials.count() == 0) {
|
||||
_credentials.append(new CredentialSettings());
|
||||
@@ -246,26 +203,9 @@ namespace Robomongo
|
||||
|
||||
std::string ConnectionSettings::getFullAddress() const
|
||||
{
|
||||
return hostAndPort().toString();
|
||||
return info().toString();
|
||||
}
|
||||
|
||||
mongo::HostAndPort ConnectionSettings::hostAndPort() const
|
||||
{
|
||||
// If it doesn't look like IPv6 address,
|
||||
// treat it like IPv4 or literal hostname
|
||||
if (_host.find(':') == std::string::npos) {
|
||||
return mongo::HostAndPort(_host, _port);
|
||||
}
|
||||
|
||||
// The following code assumes, that it is IPv6 address
|
||||
// If address contains square brackets ("["), remove them:
|
||||
std::string hostCopy = _host;
|
||||
if (_host.find('[') != std::string::npos) {
|
||||
boost::erase_all(hostCopy, "[");
|
||||
boost::erase_all(hostCopy, "]");
|
||||
}
|
||||
|
||||
return mongo::HostAndPort(hostCopy, _port);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QVariantMap>
|
||||
|
||||
#include <mongo/client/dbclientinterface.h>
|
||||
#include <mongo/client/mongo_uri.h>
|
||||
#include <mongo/util/net/hostandport.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
@@ -26,14 +24,9 @@ namespace Robomongo
|
||||
/**
|
||||
* @brief Creates ConnectionSettings with default values
|
||||
*/
|
||||
ConnectionSettings(bool isClone);
|
||||
|
||||
/**
|
||||
* @brief Creates ConnectionSettings from mongo connection string URI
|
||||
*/
|
||||
ConnectionSettings(const mongo::MongoURI& uri, bool isClone);
|
||||
ConnectionSettings();
|
||||
|
||||
explicit ConnectionSettings(QVariantMap map, bool isClone);
|
||||
explicit ConnectionSettings(QVariantMap map);
|
||||
|
||||
/**
|
||||
* @brief Cleanup used resources
|
||||
@@ -71,7 +64,7 @@ namespace Robomongo
|
||||
/**
|
||||
* @brief Port of server
|
||||
*/
|
||||
int serverPort() const { return _port; }
|
||||
unsigned short serverPort() const { return _port; }
|
||||
void setServerPort(const int port) { _port = port; }
|
||||
|
||||
/**
|
||||
@@ -100,12 +93,12 @@ namespace Robomongo
|
||||
* @brief Checks whether this connection has primary credential
|
||||
* which is also enabled.
|
||||
*/
|
||||
bool hasEnabledPrimaryCredential() const;
|
||||
bool hasEnabledPrimaryCredential();
|
||||
|
||||
/**
|
||||
* @brief Returns primary credential
|
||||
*/
|
||||
CredentialSettings *primaryCredential() const;
|
||||
CredentialSettings *primaryCredential();
|
||||
|
||||
/**
|
||||
* @brief Returns number of credentials
|
||||
@@ -140,46 +133,45 @@ namespace Robomongo
|
||||
return _connectionName;
|
||||
}
|
||||
|
||||
mongo::HostAndPort hostAndPort() const;
|
||||
SshSettings *sshSettings() const { return _sshSettings.get(); }
|
||||
SslSettings *sslSettings() const { return _sslSettings.get(); }
|
||||
ReplicaSetSettings *replicaSetSettings() const { return _replicaSetSettings.get(); }
|
||||
mongo::HostAndPort info() const {
|
||||
// If it doesn't look like IPv6 address,
|
||||
// treat it like IPv4 or literal hostname
|
||||
if (_host.find(':') == std::string::npos) {
|
||||
return mongo::HostAndPort(_host, _port);
|
||||
}
|
||||
|
||||
// The following code assumes, that it is IPv6 address
|
||||
// If address contains square brackets ("["), remove them:
|
||||
std::string hostCopy = _host;
|
||||
if (_host.find('[') != std::string::npos) {
|
||||
boost::erase_all(hostCopy, "[");
|
||||
boost::erase_all(hostCopy, "]");
|
||||
}
|
||||
|
||||
return mongo::HostAndPort(hostCopy, _port);
|
||||
}
|
||||
|
||||
SshSettings *sshSettings() const { return _sshSettings; }
|
||||
SslSettings *sslSettings() const { return _sslSettings; }
|
||||
ReplicaSetSettings *replicaSetSettings() const { return _replicaSetSettings; }
|
||||
|
||||
bool isReplicaSet() const { return _isReplicaSet; }
|
||||
void setReplicaSet(bool flag) { _isReplicaSet = flag; }
|
||||
|
||||
QString uuid() const { return _uuid; }
|
||||
void setUuid(QString const& uuid) { _uuid = uuid; }
|
||||
|
||||
private:
|
||||
CredentialSettings *findCredential(const std::string &databaseName) const;
|
||||
|
||||
bool _isReplicaSet;
|
||||
std::string _connectionName;
|
||||
std::string _host;
|
||||
int _port;
|
||||
std::string _defaultDatabase;
|
||||
mutable QList<CredentialSettings *> _credentials;
|
||||
std::unique_ptr<SshSettings> _sshSettings;
|
||||
std::unique_ptr<SslSettings> _sslSettings;
|
||||
bool _isReplicaSet;
|
||||
std::unique_ptr<ReplicaSetSettings> _replicaSetSettings;
|
||||
|
||||
QList<CredentialSettings *> _credentials;
|
||||
SshSettings *_sshSettings;
|
||||
SslSettings *_sslSettings;
|
||||
ReplicaSetSettings *_replicaSetSettings;
|
||||
|
||||
// Was this connection imported from somewhere?
|
||||
bool _imported;
|
||||
|
||||
// Flag to check if this is a clone(copy) or original ConnectionSettings
|
||||
// Note: If this is not a clone connection settings, this object is original connection
|
||||
// ConnectionSettings object which is loaded/saved into Robomongo config. file.
|
||||
bool _clone = false;
|
||||
|
||||
// If this is a clone connection settings, unique ID will be used to identify from which
|
||||
// original connection settings this object is cloned.
|
||||
// -1 for invalid(uninitialized) unique ID which should not be seen in theory
|
||||
int _uniqueId = -1;
|
||||
|
||||
// UUID string taken from QUuid.
|
||||
// It is used to identify the unique ID of a connection settings object
|
||||
QString _uuid;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,18 +6,9 @@ namespace Robomongo
|
||||
{
|
||||
|
||||
ReplicaSetSettings::ReplicaSetSettings()
|
||||
: _cachedSetName(""), _members(), _readPreference(ReadPreference::PRIMARY)
|
||||
: _members(), _readPreference(ReadPreference::PRIMARY)
|
||||
{}
|
||||
|
||||
ReplicaSetSettings::ReplicaSetSettings(const mongo::MongoURI& uri)
|
||||
: ReplicaSetSettings()
|
||||
{
|
||||
_cachedSetName = uri.getSetName();
|
||||
for (auto const& server : uri.getServers()) {
|
||||
_members.push_back(server.host() + ":" + std::to_string(server.port()));
|
||||
}
|
||||
}
|
||||
|
||||
ReplicaSetSettings *ReplicaSetSettings::clone() const
|
||||
{
|
||||
ReplicaSetSettings *cloned = new ReplicaSetSettings(*this);
|
||||
@@ -27,8 +18,6 @@ namespace Robomongo
|
||||
QVariant ReplicaSetSettings::toVariant() const
|
||||
{
|
||||
QVariantMap map;
|
||||
map.insert("setNameUserEntered", QString::fromStdString(_setNameUserEntered));
|
||||
map.insert("cachedSetName", QString::fromStdString(_cachedSetName));
|
||||
int idx = 0;
|
||||
for (std::string const& str : _members) {
|
||||
map.insert(QString::number(idx), QtUtils::toQString(str));
|
||||
@@ -40,11 +29,9 @@ namespace Robomongo
|
||||
|
||||
void ReplicaSetSettings::fromVariant(const QVariantMap &map)
|
||||
{
|
||||
setSetNameUserEntered(map.value("setNameUserEntered").toString().toStdString());
|
||||
setCachedSetName(map.value("cachedSetName").toString().toStdString());
|
||||
// Extract and set replica members
|
||||
std::vector<std::string> vec;
|
||||
auto itr = map.begin();
|
||||
auto& itr = map.begin();
|
||||
int idx = 0;
|
||||
do
|
||||
{
|
||||
@@ -57,28 +44,14 @@ namespace Robomongo
|
||||
// Extract and set read reference
|
||||
setReadPreference(static_cast<ReadPreference>(map.value("readPreference").toInt()));
|
||||
}
|
||||
|
||||
void ReplicaSetSettings::setMembers(const std::vector<std::string>& members)
|
||||
{
|
||||
_members.clear();
|
||||
for (auto const& member : members)
|
||||
_members.push_back(member);
|
||||
}
|
||||
|
||||
void ReplicaSetSettings::setMembers(const std::vector<std::pair<std::string, bool>>& membersAndHealts)
|
||||
{
|
||||
_members.clear();
|
||||
|
||||
for (auto const& memberAndHealth : membersAndHealts)
|
||||
_members.push_back(memberAndHealth.first);
|
||||
}
|
||||
|
||||
std::vector<mongo::HostAndPort> ReplicaSetSettings::membersToHostAndPort() const
|
||||
const std::vector<mongo::HostAndPort> ReplicaSetSettings::membersToHostAndPort() const
|
||||
{
|
||||
std::vector<mongo::HostAndPort> membersHostAndPort;
|
||||
for (auto const& member : _members)
|
||||
for (auto const& member : _members)
|
||||
{
|
||||
membersHostAndPort.push_back(mongo::HostAndPort(member));
|
||||
|
||||
}
|
||||
return membersHostAndPort;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <QVariantMap>
|
||||
|
||||
#include <mongo/util/net/hostandport.h>
|
||||
#include <mongo/client/mongo_uri.h>
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
@@ -16,12 +15,9 @@ namespace Robomongo
|
||||
{
|
||||
PRIMARY = 0,
|
||||
PRIMARY_PREFERRED = 1
|
||||
// todo: Add all supported read preferences
|
||||
};
|
||||
|
||||
ReplicaSetSettings();
|
||||
|
||||
ReplicaSetSettings(const mongo::MongoURI& uri);
|
||||
|
||||
/**
|
||||
* Clones Replica Set settings.
|
||||
@@ -34,33 +30,22 @@ namespace Robomongo
|
||||
QVariant toVariant() const;
|
||||
void fromVariant(const QVariantMap &map);
|
||||
|
||||
// Getters
|
||||
std::string const& setNameUserEntered() { return _setNameUserEntered; }
|
||||
std::string const& cachedSetName() { return _cachedSetName; }
|
||||
std::vector<std::string> const& members() const { return _members; }
|
||||
std::vector<mongo::HostAndPort> membersToHostAndPort() const;
|
||||
//// todo: remove
|
||||
//void addMember(const std::string& str) { _members.push_back(str); }
|
||||
|
||||
std::set<mongo::HostAndPort> membersToHostAndPortAsSet() const
|
||||
{
|
||||
auto const& members = membersToHostAndPort();
|
||||
return std::set<mongo::HostAndPort>(members.begin(), members.end());
|
||||
}
|
||||
|
||||
// Getters
|
||||
//
|
||||
const std::vector<std::string>& members() const { return _members; }
|
||||
const std::vector<mongo::HostAndPort> membersToHostAndPort() const;
|
||||
ReadPreference readPreference() const { return _readPreference; }
|
||||
|
||||
// Setters
|
||||
void setSetNameUserEntered(const std::string& setName) { _setNameUserEntered = setName; }
|
||||
void setCachedSetName(const std::string& setName) { _cachedSetName = setName; }
|
||||
void setMembers(const std::vector<std::string>& members);
|
||||
void setMembers(const std::vector<std::pair<std::string,bool>>& membersAndHealts);
|
||||
void deleteAllMembers() { _members.clear(); }
|
||||
//
|
||||
void setMembers(const std::vector<std::string>& members) { _members = members; }
|
||||
void setReadPreference(ReadPreference readPreference) { _readPreference = readPreference; }
|
||||
|
||||
|
||||
private:
|
||||
std::string _setNameUserEntered;
|
||||
std::string _cachedSetName;
|
||||
std::vector<std::string> _members;
|
||||
ReadPreference _readPreference = ReadPreference::PRIMARY;
|
||||
ReadPreference _readPreference;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,23 +3,6 @@
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QVariantList>
|
||||
#include <QUuid>
|
||||
#include <QJsonArray>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
// Todo:
|
||||
// Warning:
|
||||
// Currently, this include statement should be maintained manually.
|
||||
// The Qt version must be updated if Qt is upgraded. Otherwise it might cause build error.
|
||||
// The correct path will be: PROJECT_QT_VERSION/QtGui/private/qzipreader_p.h
|
||||
// Details:
|
||||
// Ideally, private class inside qzipreader_p.h should not be used since it is not
|
||||
// a publicly/officially supported API by Qt. It is used here since we are doing a
|
||||
// a very lightweight zip operation which is unzipping a zip archive with one, small file.
|
||||
// The alternative is including QuaZip and Zlib third party libraries into CMAKE project and
|
||||
// building, and using them which might be time consuming.
|
||||
#include <5.7.0/QtGui/private/qzipreader_p.h>
|
||||
|
||||
#include <parser.h>
|
||||
#include <serializer.h>
|
||||
|
||||
@@ -31,68 +14,29 @@
|
||||
#include "robomongo/core/utils/QtUtils.h"
|
||||
#include "robomongo/core/utils/StdUtils.h"
|
||||
#include "robomongo/gui/AppStyle.h"
|
||||
#include "robomongo/utils/common.h"
|
||||
|
||||
namespace Robomongo
|
||||
namespace
|
||||
{
|
||||
// 3T config files
|
||||
auto const Studio3T_PropertiesDat = QString("%1/.3T/studio-3t/properties.dat").arg(QDir::homePath());
|
||||
auto const DataMongodb_PropertiesDat = QString("%1/.3T/data-man-mongodb/properties.dat").arg(QDir::homePath());
|
||||
auto const MongoChefPro_PropertiesDat = QString("%1/.3T/mongochef-pro/properties.dat").arg(QDir::homePath());
|
||||
auto const MongoChefEnt_PropertiesDat = QString("%1/.3T/mongochef-enterprise/properties.dat").arg(QDir::homePath());
|
||||
/**
|
||||
* @brief Version of schema
|
||||
*/
|
||||
const QString SchemaVersion = "2.0";
|
||||
|
||||
const std::vector<std::pair<QString, QString>> S_3T_ZipFile_And_ConfigFile_List
|
||||
{
|
||||
{ Studio3T_PropertiesDat, "Studio3T.properties" },
|
||||
{ DataMongodb_PropertiesDat, "3T.data-man-mongodb.properties" },
|
||||
{ MongoChefPro_PropertiesDat, "3T.mongochef-pro.properties" },
|
||||
{ MongoChefEnt_PropertiesDat, "3T.mongochef-enterprise.properties" }
|
||||
};
|
||||
|
||||
// Extract zipFile and find the value of "anonymousID" field in propFile
|
||||
QString extractAnonymousID(QString const& zipFile, QString const& propfile);
|
||||
|
||||
/**
|
||||
* @brief Version of schema
|
||||
*/
|
||||
const QString SchemaVersion = "2.0";
|
||||
/**
|
||||
* @brief Config file absolute path
|
||||
* (usually: /home/user/.config/robomongo/robomongo.json)
|
||||
*/
|
||||
const QString _configPath = QString("%1/.config/robomongo/0.9/robomongo.json").arg(QDir::homePath());
|
||||
|
||||
/**
|
||||
* @brief Config file containing directory path
|
||||
* (usually: /home/user/.config/robomongo)
|
||||
*/
|
||||
const QString _configDir = QString("%1/.config/robomongo/0.9").arg(QDir::homePath());
|
||||
}
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Robomongo config. files
|
||||
*/
|
||||
const auto CONFIG_FILE_0_8_5 = QString("%1/.config/robomongo/robomongo.json").arg(QDir::homePath());
|
||||
const auto CONFIG_FILE_0_9 = QString("%1/.config/robomongo/0.9/robomongo.json").arg(QDir::homePath());
|
||||
const auto CONFIG_FILE_1_0_RC1 = QString("%1/.config/robomongo/1.0/robomongo.json").arg(QDir::homePath());
|
||||
// Change of path due to re-branding to 3T
|
||||
const auto CONFIG_FILE_1_0_0 = QString("%1/.3T/robomongo/1.0.0/robomongo.json").arg(QDir::homePath());
|
||||
|
||||
struct ConfigFileAndImportFunction
|
||||
{
|
||||
ConfigFileAndImportFunction(QString const& configFile, std::function<bool()> importFunction)
|
||||
: file(configFile), import(importFunction) {}
|
||||
|
||||
QString file;
|
||||
std::function<bool()> import;
|
||||
};
|
||||
|
||||
// Warning: Config. file and import function of a new release must be placed as first element of
|
||||
// vector initializer list below in order.
|
||||
std::vector<ConfigFileAndImportFunction> const SettingsManager::_configFilesAndImportFunctions
|
||||
{
|
||||
ConfigFileAndImportFunction(CONFIG_FILE_1_0_RC1, SettingsManager::importConnectionsFrom_1_0_RC1_to_1_0_0),
|
||||
ConfigFileAndImportFunction(CONFIG_FILE_0_9, SettingsManager::importConnectionsFrom_0_9_to_1_0_RC1),
|
||||
ConfigFileAndImportFunction(CONFIG_FILE_0_8_5, SettingsManager::importConnectionsFrom_0_8_5_to_0_9)
|
||||
};
|
||||
|
||||
std::vector<ConnectionSettings*> SettingsManager::_connections;
|
||||
// Temporarily disabling Recent Connections feature
|
||||
// std::vector<RecentConnection> SettingsManager::_recentConnections;
|
||||
|
||||
/**
|
||||
* Creates SettingsManager for config file in default location
|
||||
* ~/.config/robomongo/robomongo.json
|
||||
@@ -103,23 +47,18 @@ namespace Robomongo
|
||||
_timeZone(Utc),
|
||||
_viewMode(Robomongo::Tree),
|
||||
_autocompletionMode(AutocompleteAll),
|
||||
_loadMongoRcJs(false),
|
||||
_minimizeToTray(false),
|
||||
_lineNumbers(false),
|
||||
_disableConnectionShortcuts(false),
|
||||
_batchSize(50),
|
||||
_disableConnectionShortcuts(false),
|
||||
_textFontFamily(""),
|
||||
_textFontPointSize(-1),
|
||||
_lineNumbers(false),
|
||||
_loadMongoRcJs(false),
|
||||
_imported(false),
|
||||
_mongoTimeoutSec(10),
|
||||
_shellTimeoutSec(15),
|
||||
_imported(false)
|
||||
_shellTimeoutSec(15)
|
||||
{
|
||||
if (!load()) { // if load fails (probably due to non-existing config. file or directory)
|
||||
save(); // create empty settings file
|
||||
load(); // try loading again for the purpose of import from previous Robomongo versions
|
||||
}
|
||||
|
||||
LOG_MSG("SettingsManager initialized in " + ConfigFilePath, mongo::logger::LogSeverity::Info(), false);
|
||||
load();
|
||||
LOG_MSG("SettingsManager initialized in " + _configPath, mongo::logger::LogSeverity::Info(), false);
|
||||
}
|
||||
|
||||
SettingsManager::~SettingsManager()
|
||||
@@ -133,10 +72,10 @@ namespace Robomongo
|
||||
*/
|
||||
bool SettingsManager::load()
|
||||
{
|
||||
if (!QFile::exists(ConfigFilePath))
|
||||
if (!QFile::exists(_configPath))
|
||||
return false;
|
||||
|
||||
QFile f(ConfigFilePath);
|
||||
QFile f(_configPath);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
return false;
|
||||
|
||||
@@ -159,14 +98,14 @@ namespace Robomongo
|
||||
{
|
||||
QVariantMap map = convertToMap();
|
||||
|
||||
if (!QDir().mkpath(ConfigDir)) {
|
||||
LOG_MSG("ERROR: Could not create settings path: " + ConfigDir, mongo::logger::LogSeverity::Error());
|
||||
if (!QDir().mkpath(_configDir)) {
|
||||
LOG_MSG("ERROR: Could not create settings path: " + _configDir, mongo::logger::LogSeverity::Error());
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile f(ConfigFilePath);
|
||||
QFile f(_configPath);
|
||||
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
LOG_MSG("ERROR: Could not write settings to: " + ConfigFilePath, mongo::logger::LogSeverity::Error());
|
||||
LOG_MSG("ERROR: Could not write settings to: " + _configPath, mongo::logger::LogSeverity::Error());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -175,21 +114,11 @@ namespace Robomongo
|
||||
s.setIndentMode(QJson::IndentFull);
|
||||
s.serialize(map, &f, &ok);
|
||||
|
||||
LOG_MSG("Settings saved to: " + ConfigFilePath, mongo::logger::LogSeverity::Info());
|
||||
LOG_MSG("Settings saved to: " + _configPath, mongo::logger::LogSeverity::Info());
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void SettingsManager::addCacheData(QString const& key, QVariant const& value)
|
||||
{
|
||||
_cacheData.insert(key, value);
|
||||
}
|
||||
|
||||
QVariant SettingsManager::cacheData(QString const& key) const
|
||||
{
|
||||
return _cacheData.value(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load settings from the map. Existings settings will be overwritten.
|
||||
*/
|
||||
@@ -203,7 +132,7 @@ namespace Robomongo
|
||||
if (encoding > 3 || encoding < 0)
|
||||
encoding = 0;
|
||||
|
||||
_uuidEncoding = (UUIDEncoding)encoding;
|
||||
_uuidEncoding = (UUIDEncoding) encoding;
|
||||
|
||||
|
||||
// 3. Load view mode
|
||||
@@ -211,41 +140,39 @@ namespace Robomongo
|
||||
int viewMode = map.value("viewMode").toInt();
|
||||
if (viewMode > 2 || viewMode < 0)
|
||||
viewMode = Custom; // Default View Mode
|
||||
_viewMode = (ViewMode)viewMode;
|
||||
}
|
||||
else {
|
||||
_viewMode = (ViewMode) viewMode;
|
||||
} else {
|
||||
_viewMode = Custom; // Default View Mode
|
||||
}
|
||||
|
||||
_autoExpand = map.contains("autoExpand") ? map.value("autoExpand").toBool() : true;
|
||||
_autoExec = map.contains("autoExec") ? map.value("autoExec").toBool() : true;
|
||||
_minimizeToTray = map.contains("minimizeToTray") ? map.value("minimizeToTray").toBool() : false;
|
||||
_lineNumbers = map.contains("lineNumbers") ? map.value("lineNumbers").toBool() : false;
|
||||
_imported = map.contains("imported") ? map.value("imported").toBool() : false;
|
||||
_autoExpand = map.contains("autoExpand") ?
|
||||
map.value("autoExpand").toBool() : true;
|
||||
|
||||
_autoExec = map.contains("autoExec") ?
|
||||
map.value("autoExec").toBool() : true;
|
||||
|
||||
_lineNumbers = map.contains("lineNumbers") ?
|
||||
map.value("lineNumbers").toBool() : false;
|
||||
|
||||
_imported = map.contains("imported") ?
|
||||
map.value("imported").toBool() : false;
|
||||
|
||||
// 4. Load TimeZone
|
||||
int timeZone = map.value("timeZone").toInt();
|
||||
if (timeZone > 1 || timeZone < 0)
|
||||
timeZone = 0;
|
||||
|
||||
_timeZone = (SupportedTimes)timeZone;
|
||||
_timeZone = (SupportedTimes) timeZone;
|
||||
_loadMongoRcJs = map.value("loadMongoRcJs").toBool();
|
||||
_disableConnectionShortcuts = map.value("disableConnectionShortcuts").toBool();
|
||||
|
||||
if (map.contains("acceptedEulaVersions"))
|
||||
_acceptedEulaVersions = map.value("acceptedEulaVersions").toStringList().toSet();
|
||||
|
||||
// Load anonymousID
|
||||
_anonymousID = getOrCreateAnonymousID(map);
|
||||
|
||||
// Load AutocompletionMode
|
||||
if (map.contains("autocompletionMode")) {
|
||||
int autocompletionMode = map.value("autocompletionMode").toInt();
|
||||
if (autocompletionMode < 0 || autocompletionMode > 2)
|
||||
autocompletionMode = AutocompleteAll; // Default Mode
|
||||
_autocompletionMode = (AutocompletionMode)autocompletionMode;
|
||||
}
|
||||
else {
|
||||
_autocompletionMode = (AutocompletionMode) autocompletionMode;
|
||||
} else {
|
||||
_autocompletionMode = AutocompleteAll; // Default Mode
|
||||
}
|
||||
|
||||
@@ -253,10 +180,6 @@ namespace Robomongo
|
||||
_batchSize = map.value("batchSize").toInt();
|
||||
if (_batchSize == 0)
|
||||
_batchSize = 50;
|
||||
|
||||
if (map.contains("checkForUpdates"))
|
||||
_checkForUpdates = map.value("checkForUpdates").toBool();
|
||||
|
||||
_currentStyle = map.value("style").toString();
|
||||
if (_currentStyle.isEmpty()) {
|
||||
_currentStyle = AppStyle::StyleName;
|
||||
@@ -277,48 +200,33 @@ namespace Robomongo
|
||||
// 5. Load connections
|
||||
_connections.clear();
|
||||
|
||||
QVariantList const& list = map.value("connections").toList();
|
||||
for (auto const& conn : list) {
|
||||
auto connSettings = new ConnectionSettings(false);
|
||||
connSettings->fromVariant(conn.toMap());
|
||||
addConnection(connSettings);
|
||||
QVariantList list = map.value("connections").toList();
|
||||
for (QVariantList::iterator it = list.begin(); it != list.end(); ++it) {
|
||||
ConnectionSettings *record = new ConnectionSettings();
|
||||
record->fromVariant((*it).toMap());
|
||||
addConnection(record);
|
||||
}
|
||||
|
||||
/* Temporarily disabling Recent Connections feature
|
||||
// Load recent connections
|
||||
_recentConnections.clear();
|
||||
QVariantList const& rlist = map.value("recentConnections").toList();
|
||||
for (auto const& rconn : rlist) {
|
||||
_recentConnections.push_back(RecentConnection(rconn.toMap().value("uuid").toString(),
|
||||
rconn.toMap().value("name").toString().toStdString()));
|
||||
}
|
||||
*/
|
||||
|
||||
_toolbars = map.value("toolbars").toMap();
|
||||
ToolbarSettingsContainerType::const_iterator it = _toolbars.find("connect");
|
||||
if (_toolbars.end() == it)
|
||||
_toolbars["connect"] = true;
|
||||
|
||||
it = _toolbars.find("open_save");
|
||||
if (_toolbars.end() == it)
|
||||
_toolbars["open_save"] = true;
|
||||
|
||||
it = _toolbars.find("exec");
|
||||
if (_toolbars.end() == it)
|
||||
_toolbars["exec"] = true;
|
||||
|
||||
it = _toolbars.find("explorer");
|
||||
if (_toolbars.end() == it)
|
||||
_toolbars["explorer"] = true;
|
||||
|
||||
it = _toolbars.find("logs");
|
||||
if (_toolbars.end() == it)
|
||||
_toolbars["logs"] = false;
|
||||
|
||||
_cacheData = map.value("cacheData").toMap();
|
||||
|
||||
// Load connection settings from previous versions of Robomongo
|
||||
importConnections();
|
||||
// Load connection settings from previous
|
||||
// versions of Robomongo
|
||||
importPreviousConnections();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -350,84 +258,40 @@ namespace Robomongo
|
||||
|
||||
// 7. Save disableConnectionShortcuts
|
||||
map.insert("disableConnectionShortcuts", _disableConnectionShortcuts);
|
||||
|
||||
// 8. Save acceptedEulaVersions array
|
||||
QJsonArray arr;
|
||||
for (auto const& str : _acceptedEulaVersions)
|
||||
arr.push_back(str);
|
||||
|
||||
map.insert("acceptedEulaVersions", arr.toVariantList());
|
||||
|
||||
// 9. Save batchSize
|
||||
// 8. Save batchSize
|
||||
map.insert("batchSize", _batchSize);
|
||||
map.insert("checkForUpdates", _checkForUpdates);
|
||||
map.insert("mongoTimeoutSec", _mongoTimeoutSec);
|
||||
map.insert("shellTimeoutSec", _shellTimeoutSec);
|
||||
|
||||
// 10. Save style
|
||||
// 9. Save style
|
||||
map.insert("style", _currentStyle);
|
||||
|
||||
// 11. Save font information
|
||||
// 10. Save font information
|
||||
map.insert("textFontFamily", _textFontFamily);
|
||||
map.insert("textFontPointSize", _textFontPointSize);
|
||||
|
||||
// 12. Save connections
|
||||
// 11. Save connections
|
||||
QVariantList list;
|
||||
for (auto const conn : _connections)
|
||||
list.append(conn->toVariant().toMap());
|
||||
|
||||
for (ConnectionSettingsContainerType::const_iterator it = _connections.begin(); it != _connections.end(); ++it) {
|
||||
QVariantMap rm = (*it)->toVariant().toMap();
|
||||
list.append(rm);
|
||||
}
|
||||
|
||||
map.insert("connections", list);
|
||||
|
||||
/* Temporarily disabling Recent Connections feature
|
||||
// 13. Save recent connections
|
||||
QVariantList recentConnsList;
|
||||
QVariantMap recentConnMap;
|
||||
for (auto const& rconn : _recentConnections) {
|
||||
recentConnMap.insert("uuid", rconn.uuid);
|
||||
recentConnMap.insert("name", QString::fromStdString(rconn.name));
|
||||
recentConnsList.append(recentConnMap);
|
||||
}
|
||||
map.insert("recentConnections", recentConnsList);
|
||||
*/
|
||||
|
||||
map.insert("autoExec", _autoExec);
|
||||
map.insert("minimizeToTray", _minimizeToTray);
|
||||
|
||||
map.insert("toolbars", _toolbars);
|
||||
|
||||
map.insert("imported", _imported);
|
||||
map.insert("anonymousID", _anonymousID);
|
||||
map.insert("cacheData", _cacheData);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
QString SettingsManager::getOrCreateAnonymousID(QVariantMap const& map) const
|
||||
{
|
||||
QString anonymousID = "";
|
||||
|
||||
// If anonymousID has never been created or is empty, create a new one. Otherwise load the existing.
|
||||
if (map.contains("anonymousID")) {
|
||||
QUuid id = map.value("anonymousID").toString();
|
||||
if (!id.isNull())
|
||||
anonymousID = id.toString();
|
||||
}
|
||||
|
||||
for (auto const& zipFileAndConfigFile : S_3T_ZipFile_And_ConfigFile_List) {
|
||||
if (!anonymousID.isEmpty())
|
||||
break;
|
||||
|
||||
QUuid const& id = extractAnonymousID(zipFileAndConfigFile.first, zipFileAndConfigFile.second);
|
||||
if (!id.isNull())
|
||||
anonymousID = id.toString();
|
||||
}
|
||||
|
||||
if (anonymousID.isEmpty())
|
||||
anonymousID = QUuid::createUuid().toString();
|
||||
|
||||
return anonymousID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds connection to the end of list and set it's uniqueID
|
||||
* Adds connection to the end of list
|
||||
*/
|
||||
void SettingsManager::addConnection(ConnectionSettings *connection)
|
||||
{
|
||||
@@ -446,50 +310,6 @@ namespace Robomongo
|
||||
}
|
||||
}
|
||||
|
||||
/* Temporarily disabling Recent Connections feature
|
||||
void SettingsManager::addRecentConnection(ConnectionSettings *connection)
|
||||
{
|
||||
_recentConnections.push_back(RecentConnection(connection->uuid(), connection->connectionName()));
|
||||
}
|
||||
|
||||
void SettingsManager::deleteRecentConnection(ConnectionSettings *conn)
|
||||
{
|
||||
for (int i = 0; i < _recentConnections.size(); ++i) {
|
||||
if (_recentConnections[i].uuid == conn->uuid())
|
||||
_recentConnections.erase(_recentConnections.begin() + i);
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsManager::setRecentConnections(std::vector<ConnectionSettings const*> const& recentConns)
|
||||
{
|
||||
_recentConnections.clear();
|
||||
|
||||
for(auto rconn : recentConns)
|
||||
_recentConnections.push_back(RecentConnection(rconn->uuid(), rconn->connectionName()));
|
||||
}
|
||||
|
||||
void SettingsManager::clearRecentConnections()
|
||||
{
|
||||
_recentConnections.clear();
|
||||
}
|
||||
*/
|
||||
|
||||
ConnectionSettings* SettingsManager::getConnectionSettingsByUuid(QString const& uuid) const
|
||||
{
|
||||
for (auto const connSettings : _connections){
|
||||
if (connSettings->uuid() == uuid)
|
||||
return connSettings;
|
||||
}
|
||||
|
||||
LOG_MSG("Failed to find connection settings object by UUID.", mongo::logger::LogSeverity::Warning());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ConnectionSettings* SettingsManager::getConnectionSettingsByUuid(std::string const& uuid) const
|
||||
{
|
||||
return getConnectionSettingsByUuid(QString::fromStdString(uuid));
|
||||
}
|
||||
|
||||
void SettingsManager::setCurrentStyle(const QString& style)
|
||||
{
|
||||
_currentStyle = style;
|
||||
@@ -514,45 +334,32 @@ namespace Robomongo
|
||||
_toolbars[toolbarName] = visible;
|
||||
}
|
||||
|
||||
void SettingsManager::importConnections()
|
||||
{
|
||||
void SettingsManager::importPreviousConnections() {
|
||||
// Skip when settings already imported
|
||||
if (_imported)
|
||||
return;
|
||||
|
||||
// Find and import 'only' from the latest version
|
||||
for (auto const& configFileAndImportFunction : _configFilesAndImportFunctions) {
|
||||
if (QFile::exists(configFileAndImportFunction.file)) {
|
||||
configFileAndImportFunction.import();
|
||||
setImported(true); // Mark as imported
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SettingsManager::importConnectionsFrom_0_8_5_to_0_9()
|
||||
{
|
||||
// Load old configuration file (used till version 0.8.5)
|
||||
const QString oldConfigPath = QString("%1/.config/robomongo/robomongo.json").arg(QDir::homePath());
|
||||
|
||||
if (!QFile::exists(CONFIG_FILE_0_8_5))
|
||||
return false;
|
||||
if (!QFile::exists(oldConfigPath))
|
||||
return;
|
||||
|
||||
QFile oldConfigFile(CONFIG_FILE_0_8_5);
|
||||
if (!oldConfigFile.open(QIODevice::ReadOnly))
|
||||
return false;
|
||||
QFile f(oldConfigPath);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
return;
|
||||
|
||||
bool ok;
|
||||
QJson::Parser parser;
|
||||
QVariantMap vmap = parser.parse(oldConfigFile.readAll(), &ok).toMap();
|
||||
QVariantMap vmap = parser.parse(f.readAll(), &ok).toMap();
|
||||
if (!ok)
|
||||
return false;
|
||||
return;
|
||||
|
||||
QVariantList vconns = vmap.value("connections").toList();
|
||||
for (QVariantList::iterator itconn = vconns.begin(); itconn != vconns.end(); ++itconn)
|
||||
{
|
||||
for (QVariantList::iterator itconn = vconns.begin(); itconn != vconns.end(); ++itconn) {
|
||||
QVariantMap vconn = (*itconn).toMap();
|
||||
|
||||
auto conn = new ConnectionSettings(false);
|
||||
ConnectionSettings *conn = new ConnectionSettings();
|
||||
conn->setImported(true);
|
||||
conn->setConnectionName(QtUtils::toStdString(vconn.value("connectionName").toString()));
|
||||
conn->setServerHost(QtUtils::toStdString(vconn.value("serverHost").toString().left(300)));
|
||||
@@ -587,7 +394,7 @@ namespace Robomongo
|
||||
for (QVariantList::const_iterator itcred = vcreds.begin(); itcred != vcreds.end(); ++itcred) {
|
||||
QVariantMap vcred = (*itcred).toMap();
|
||||
|
||||
auto cred = new CredentialSettings();
|
||||
CredentialSettings *cred = new CredentialSettings();
|
||||
cred->setUserName(QtUtils::toStdString(vcred.value("userName").toString()));
|
||||
cred->setUserPassword(QtUtils::toStdString(vcred.value("userPassword").toString()));
|
||||
cred->setDatabaseName(QtUtils::toStdString(vcred.value("databaseName").toString()));
|
||||
@@ -634,46 +441,8 @@ namespace Robomongo
|
||||
addConnection(conn);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SettingsManager::importConnectionsFrom_0_9_to_1_0_RC1()
|
||||
{
|
||||
return importConnectionsFromOldVersion(CONFIG_FILE_0_9);
|
||||
}
|
||||
|
||||
bool SettingsManager::importConnectionsFrom_1_0_RC1_to_1_0_0()
|
||||
{
|
||||
return importConnectionsFromOldVersion(CONFIG_FILE_1_0_RC1);
|
||||
}
|
||||
|
||||
bool SettingsManager::importConnectionsFromOldVersion(QString const& oldConfigFilePath)
|
||||
{
|
||||
if (!QFile::exists(oldConfigFilePath))
|
||||
return false;
|
||||
|
||||
QFile oldConfigFile(oldConfigFilePath);
|
||||
if (!oldConfigFile.open(QIODevice::ReadOnly))
|
||||
return false;
|
||||
|
||||
bool ok;
|
||||
QJson::Parser parser;
|
||||
QVariantMap vmap = parser.parse(oldConfigFile.readAll(), &ok).toMap();
|
||||
if (!ok)
|
||||
return false;
|
||||
|
||||
QVariantList const& vconns = vmap.value("connections").toList();
|
||||
for (auto const& vcon : vconns)
|
||||
{
|
||||
QVariantMap const& vconn = vcon.toMap();
|
||||
auto connSettings = new ConnectionSettings(false);
|
||||
connSettings->fromVariant(vconn);
|
||||
connSettings->setImported(true);
|
||||
|
||||
addConnection(connSettings);
|
||||
}
|
||||
|
||||
return true;
|
||||
// Mark as imported
|
||||
setImported(true);
|
||||
}
|
||||
|
||||
int SettingsManager::importedConnectionsCount() {
|
||||
@@ -686,26 +455,4 @@ namespace Robomongo
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
QString extractAnonymousID(QString const& zipFile, QString const& propfile)
|
||||
{
|
||||
QZipReader zipReader(zipFile);
|
||||
if (!zipReader.exists() || !zipReader.isReadable())
|
||||
return QString("");
|
||||
|
||||
QXmlStreamReader reader(zipReader.fileData(propfile));
|
||||
while (!reader.atEnd()) {
|
||||
reader.readNext();
|
||||
if (reader.text().toString() == "AnonymousID") {
|
||||
reader.readNext();
|
||||
reader.readNext();
|
||||
reader.readNext();
|
||||
reader.readNext();
|
||||
return reader.text().toString();
|
||||
}
|
||||
}
|
||||
|
||||
return QString("");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,46 +2,12 @@
|
||||
|
||||
#include <QString>
|
||||
#include <QVariantMap>
|
||||
#include <QSet>
|
||||
#include <QDir>
|
||||
#include <vector>
|
||||
#include "robomongo/core/Enums.h"
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
class ConnectionSettings;
|
||||
struct ConfigFileAndImportFunction;
|
||||
|
||||
// Current cache directory
|
||||
QString const CacheDir = QString("%1/.3T/robomongo/%2/cache/").arg(QDir::homePath())
|
||||
.arg(PROJECT_VERSION);
|
||||
// Current config file
|
||||
QString const ConfigFilePath = QString("%1/.3T/robomongo/%2/robomongo.json").arg(QDir::homePath())
|
||||
.arg(PROJECT_VERSION);
|
||||
// Current config file directory
|
||||
QString const ConfigDir = QString("%1/.3T/robomongo/%2/").arg(QDir::homePath())
|
||||
.arg(PROJECT_VERSION);
|
||||
/* Temporarily disabling Recent Connections feature
|
||||
struct RecentConnection
|
||||
{
|
||||
RecentConnection(QString const& uuid, std::string const& name)
|
||||
: uuid(uuid), name(name) {}
|
||||
|
||||
// Not directly used but required by std::vector<T>::erase()
|
||||
RecentConnection& operator=(const RecentConnection& other)
|
||||
{
|
||||
uuid = other.uuid;
|
||||
name = other.name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
QString uuid;
|
||||
std::string name;
|
||||
};
|
||||
*/
|
||||
|
||||
/* ----------------------------- SettingsManager ------------------------------ */
|
||||
|
||||
/**
|
||||
* @brief SettingsManager gives you access to all settings, that is used
|
||||
* by Robomongo. It can load() and save() them. Config file usually
|
||||
@@ -57,7 +23,6 @@ namespace Robomongo
|
||||
public:
|
||||
typedef std::vector<ConnectionSettings *> ConnectionSettingsContainerType;
|
||||
typedef QMap<QString, QVariant> ToolbarSettingsContainerType;
|
||||
|
||||
/**
|
||||
* @brief Creates SettingsManager for config file in default location
|
||||
* (usually ~/.config/robomongo/robomongo.json)
|
||||
@@ -85,32 +50,13 @@ namespace Robomongo
|
||||
* @brief Adds connection to the end of list.
|
||||
* Connection now will be owned by SettingsManager.
|
||||
*/
|
||||
static void addConnection(ConnectionSettings *connection);
|
||||
void addConnection(ConnectionSettings *connection);
|
||||
|
||||
/**
|
||||
* @brief Removes connection by index
|
||||
*/
|
||||
void removeConnection(ConnectionSettings *connection);
|
||||
|
||||
/**
|
||||
* @brief Functions of Recent Connections feature
|
||||
*/
|
||||
/* Temporarily disabling Recent Connections feature
|
||||
static void addRecentConnection(ConnectionSettings *connection);
|
||||
static void deleteRecentConnection(ConnectionSettings *connection);
|
||||
static void setRecentConnections(std::vector<ConnectionSettings const*> const& recentConns);
|
||||
static void clearRecentConnections();
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Finds and returns original (non-clone) connection settings which is
|
||||
* loaded/saved from/into Robomongo config. file.
|
||||
* @return If uniqueID is valid returns original connection settings,
|
||||
* nullptr otherwise.
|
||||
*/
|
||||
ConnectionSettings* getConnectionSettingsByUuid(QString const& uuid) const;
|
||||
ConnectionSettings* getConnectionSettingsByUuid(std::string const& uuid) const;
|
||||
|
||||
void reorderConnections(const ConnectionSettingsContainerType &connections);
|
||||
|
||||
void setToolbarSettings(QString toolbarName, bool visible);
|
||||
@@ -119,9 +65,6 @@ namespace Robomongo
|
||||
* @brief Returns list of connections
|
||||
*/
|
||||
ConnectionSettingsContainerType connections() const { return _connections; }
|
||||
|
||||
// Temporarily disabling Recent Connections feature
|
||||
// std::vector<RecentConnection>& recentConnections() const { return _recentConnections; }
|
||||
|
||||
ToolbarSettingsContainerType toolbars() const { return _toolbars; }
|
||||
|
||||
@@ -143,9 +86,6 @@ namespace Robomongo
|
||||
void setAutoExec(bool isAutoExec) { _autoExec = isAutoExec; }
|
||||
bool autoExec() const { return _autoExec; }
|
||||
|
||||
void setMinimizeToTray(bool isMinimizingToTray) { _minimizeToTray = isMinimizingToTray; }
|
||||
bool minimizeToTray() const { return _minimizeToTray; }
|
||||
|
||||
void setLineNumbers(bool showLineNumbers) { _lineNumbers = showLineNumbers; }
|
||||
bool lineNumbers() const { return _lineNumbers; }
|
||||
|
||||
@@ -155,12 +95,6 @@ namespace Robomongo
|
||||
void setDisableConnectionShortcuts(bool isDisable) { _disableConnectionShortcuts = isDisable; }
|
||||
bool disableConnectionShortcuts() const { return _disableConnectionShortcuts; }
|
||||
|
||||
void addAcceptedEulaVersion(QString const& version) { _acceptedEulaVersions.insert(version); }
|
||||
QSet<QString> const& acceptedEulaVersions() const { return _acceptedEulaVersions; }
|
||||
|
||||
void setCheckForUpdates(bool checkForUpdates) { _checkForUpdates = checkForUpdates; }
|
||||
bool checkForUpdates() const { return _checkForUpdates; }
|
||||
|
||||
void setBatchSize(int batchSize) { _batchSize = batchSize; }
|
||||
int batchSize() const { return _batchSize; }
|
||||
|
||||
@@ -176,20 +110,15 @@ namespace Robomongo
|
||||
int mongoTimeoutSec() const { return _mongoTimeoutSec; }
|
||||
int shellTimeoutSec() const { return _shellTimeoutSec; }
|
||||
|
||||
// True when settings from previous versions of Robomongo are imported
|
||||
// True when settings from previous versions of
|
||||
// Robomongo are imported
|
||||
void setImported(bool imported) { _imported = imported; }
|
||||
bool imported() const { return _imported; }
|
||||
|
||||
QString anonymousID() const { return _anonymousID; }
|
||||
|
||||
void addCacheData(QString const& key, QVariant const& value);
|
||||
QVariant cacheData(QString const& key) const;
|
||||
|
||||
/**
|
||||
* Returns number of imported connections
|
||||
*/
|
||||
int importedConnectionsCount();
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
@@ -202,21 +131,10 @@ namespace Robomongo
|
||||
*/
|
||||
QVariantMap convertToMap() const;
|
||||
|
||||
// Find existing anonymousID from Robomongo and 3T config files, if not found create
|
||||
// a new anonymousID.
|
||||
QString getOrCreateAnonymousID(QVariantMap const& map) const;
|
||||
|
||||
/**
|
||||
* Load connection settings from previous versions of Robomongo
|
||||
*/
|
||||
void importConnections();
|
||||
|
||||
// Imports connections from oldConfigFilePath into current config file
|
||||
static bool importConnectionsFromOldVersion(QString const& oldConfigFilePath);
|
||||
|
||||
static bool importConnectionsFrom_0_8_5_to_0_9();
|
||||
static bool importConnectionsFrom_0_9_to_1_0_RC1();
|
||||
static bool importConnectionsFrom_1_0_RC1_to_1_0_0();
|
||||
void importPreviousConnections();
|
||||
|
||||
/**
|
||||
* @brief Version of settings schema currently loaded
|
||||
@@ -230,12 +148,9 @@ namespace Robomongo
|
||||
bool _loadMongoRcJs;
|
||||
bool _autoExpand;
|
||||
bool _autoExec;
|
||||
bool _minimizeToTray;
|
||||
bool _lineNumbers;
|
||||
bool _disableConnectionShortcuts;
|
||||
QSet<QString> _acceptedEulaVersions;
|
||||
int _batchSize;
|
||||
bool _checkForUpdates = true;
|
||||
QString _currentStyle;
|
||||
QString _textFontFamily;
|
||||
int _textFontPointSize;
|
||||
@@ -243,33 +158,14 @@ namespace Robomongo
|
||||
int _mongoTimeoutSec;
|
||||
int _shellTimeoutSec;
|
||||
|
||||
// True when settings from previous versions of Robomongo are imported
|
||||
// True when settings from previous versions of
|
||||
// Robomongo are imported
|
||||
bool _imported;
|
||||
|
||||
/**
|
||||
* @brief This is an anonymous string taken from QUuid that is generated when Robomongo
|
||||
* is first installed on a user's machine and then launched for the first time
|
||||
* It stays the same throughout all upgrades.
|
||||
*/
|
||||
QString _anonymousID;
|
||||
|
||||
// Various cache data
|
||||
QMap<QString, QVariant> _cacheData;
|
||||
|
||||
/**
|
||||
* @brief List of connections
|
||||
*/
|
||||
static std::vector<ConnectionSettings*> _connections;
|
||||
|
||||
/* Temporarily disabling Recent Connections feature
|
||||
// List of recent connections that are shown on Welcome Tab
|
||||
static std::vector<RecentConnection> _recentConnections;
|
||||
*/
|
||||
|
||||
ConnectionSettingsContainerType _connections;
|
||||
ToolbarSettingsContainerType _toolbars;
|
||||
|
||||
// List of config. file absolute paths and related import functions.
|
||||
// Must be updated with care and with every new version. Details on cpp file.
|
||||
static const std::vector<ConfigFileAndImportFunction> _configFilesAndImportFunctions;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -80,7 +80,6 @@ namespace Robomongo
|
||||
s << (isArray ? "[" : "{");
|
||||
BSONObjIterator i(obj);
|
||||
BSONElement e = i.next();
|
||||
|
||||
if ( !e.eoo() ) {
|
||||
while ( 1 ) {
|
||||
if ( pretty ) {
|
||||
@@ -92,7 +91,6 @@ namespace Robomongo
|
||||
else {
|
||||
s << " ";
|
||||
}
|
||||
|
||||
s << jsonString(e, format, true, pretty ? pretty + 1 : 0, uuidEncoding, timeFormat, isArray);
|
||||
e = i.next();
|
||||
|
||||
@@ -111,8 +109,7 @@ namespace Robomongo
|
||||
return s.str();
|
||||
}
|
||||
|
||||
std::string jsonString(const BSONElement &elem, JsonStringFormat format, bool includeFieldNames,
|
||||
int pretty, UUIDEncoding uuidEncoding, SupportedTimes timeFormat, bool isArray)
|
||||
std::string jsonString(const BSONElement &elem, JsonStringFormat format, bool includeFieldNames, int pretty, UUIDEncoding uuidEncoding, SupportedTimes timeFormat, bool isArray)
|
||||
{
|
||||
using namespace std;
|
||||
BSONType t = elem.type();
|
||||
@@ -334,11 +331,12 @@ namespace Robomongo
|
||||
break;
|
||||
|
||||
case bsonTimestamp:
|
||||
if ( format == TenGen )
|
||||
s << "Timestamp(" << elem.timestamp().getSecs() << ", " << elem.timestampInc() << ")";
|
||||
else
|
||||
s << "{ \"$timestamp\" : { \"t\" : " << elem.timestamp().getSecs() << ", \"i\" : "
|
||||
<< elem.timestampInc() << " } }";
|
||||
if ( format == TenGen ) {
|
||||
s << "Timestamp(" << ( elem.timestampValue() / 1000 ) << ", " << elem.timestampInc() << ")";
|
||||
}
|
||||
else {
|
||||
s << "{ \"$timestamp\" : { \"t\" : " << ( elem.timestampValue() / 1000 ) << ", \"i\" : " << elem.timestampInc() << " } }";
|
||||
}
|
||||
break;
|
||||
|
||||
case MinKey:
|
||||
|
||||
@@ -2,16 +2,13 @@
|
||||
|
||||
#include <QDir>
|
||||
#include <QMetaType>
|
||||
|
||||
#include "robomongo/core/utils/QtUtils.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string getLoggerPath()
|
||||
{
|
||||
static std::string path =
|
||||
Robomongo::QtUtils::toStdString(QString("%1/" PROJECT_NAME_LOWERCASE ".log").arg(QDir::tempPath()));
|
||||
|
||||
static std::string path = Robomongo::QtUtils::toStdString(QString("%1/" PROJECT_NAME_LOWERCASE ".log").arg(QDir::tempPath()));
|
||||
return path;
|
||||
}
|
||||
}
|
||||
@@ -49,15 +46,7 @@ namespace Robomongo
|
||||
{
|
||||
// v0.9
|
||||
// LOG(level) << "[" PROJECT_NAME_TITLE "] " << QtUtils::toStdString(mess) << std::endl;
|
||||
if (notify) {
|
||||
// Make uniform log level strings e.g "Error: ", "Info: " etc...
|
||||
auto logLevelStr = QString::fromStdString(level.toStringData().toString());
|
||||
if (!logLevelStr.isEmpty()) {
|
||||
logLevelStr = logLevelStr.toLower();
|
||||
logLevelStr[0] = logLevelStr[0].toUpper();
|
||||
logLevelStr += ": ";
|
||||
}
|
||||
emit printed(logLevelStr + mess, level);
|
||||
}
|
||||
if (notify)
|
||||
emit printed(mess, level);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,30 +44,12 @@ namespace Robomongo
|
||||
return importedIcon;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::serverPrimaryIcon() const
|
||||
{
|
||||
static const QIcon icon(":/robomongo/icons/server_primary_16x16.png");
|
||||
return icon;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::serverSecondaryIcon() const
|
||||
{
|
||||
static const QIcon icon(":/robomongo/icons/server_secondary_16x16.png");
|
||||
return icon;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::replicaSetIcon() const
|
||||
{
|
||||
static const QIcon replicaSetIc(":/robomongo/icons/replica_set_16x16.png");
|
||||
static const QIcon replicaSetIc = QIcon(":/robomongo/icons/replica_set_16x16.png");
|
||||
return replicaSetIc;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::replicaSetOfflineIcon() const
|
||||
{
|
||||
static const QIcon icon(":/robomongo/icons/replica_set_offline_16x16.png");
|
||||
return icon;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::openIcon() const
|
||||
{
|
||||
static const QIcon openIc = qApp->style()->standardIcon(QStyle::SP_DialogOpenButton);
|
||||
@@ -114,26 +96,14 @@ namespace Robomongo
|
||||
|
||||
const QIcon &GuiRegistry::maximizeIcon() const
|
||||
{
|
||||
static const QIcon maximizeIc(":/robomongo/icons/maximize.png");
|
||||
static const QIcon maximizeIc = QIcon(":/robomongo/icons/maximize.gif");
|
||||
return maximizeIc;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::minimizeIcon() const
|
||||
const QIcon &GuiRegistry::maximizeHighlightedIcon() const
|
||||
{
|
||||
static const QIcon minimizeIc(":/robomongo/icons/minimize.png");
|
||||
return minimizeIc;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::undockIcon() const
|
||||
{
|
||||
static const QIcon undockIc(":/robomongo/icons/undock.png");
|
||||
return undockIc;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::dockIcon() const
|
||||
{
|
||||
static const QIcon dockIc(":/robomongo/icons/dock.png");
|
||||
return dockIc;
|
||||
static const QIcon maximizeHighlightedIc = QIcon(":/robomongo/icons/maximize_highlighted_16x16.png");
|
||||
return maximizeHighlightedIc;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::textIcon() const
|
||||
@@ -311,18 +281,6 @@ namespace Robomongo
|
||||
return icon;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::plusIcon() const
|
||||
{
|
||||
static const QIcon icon {":/robomongo/icons/plus_sign.png"};
|
||||
return icon;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::minusIcon() const
|
||||
{
|
||||
static const QIcon icon {":/robomongo/icons/minus_sign.png"};
|
||||
return icon;
|
||||
}
|
||||
|
||||
const QBrush &GuiRegistry::typeBrush() const
|
||||
{
|
||||
static const QBrush typeBrush = QBrush(QColor(150, 150, 150));
|
||||
@@ -347,12 +305,6 @@ namespace Robomongo
|
||||
static const QIcon mongodbIc = QIcon(":/robomongo/icons/mongodb_16x16.png");
|
||||
return mongodbIc;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::mongodbIconForMAC() const
|
||||
{
|
||||
static const QIcon mongodbIc = QIcon(":/robomongo/icons/mongodb_icon_for_MAC.png");
|
||||
return mongodbIc;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::connectIcon() const
|
||||
{
|
||||
@@ -384,36 +336,13 @@ namespace Robomongo
|
||||
return importIc;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::deleteIcon() const
|
||||
{
|
||||
static const QIcon icon(":/robomongo/icons/delete.png");
|
||||
return icon;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::deleteIconRed() const
|
||||
{
|
||||
static const QIcon icon(":/robomongo/icons/delete_red_color.png");
|
||||
return icon;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::deleteIconMouseHovered() const
|
||||
{
|
||||
static const QIcon icon(":/robomongo/icons/delete_mouse_hovered.png");
|
||||
return icon;
|
||||
}
|
||||
|
||||
const QIcon &GuiRegistry::mainWindowIcon() const
|
||||
{
|
||||
static const QIcon mainWindowIc = QIcon(":/robomongo/icons/logo-256x256.png");
|
||||
// static const QIcon mainWindowIc = QIcon(":/robomongo/icons/main_window_icon.png");
|
||||
return mainWindowIc;
|
||||
}
|
||||
|
||||
const QIcon& GuiRegistry::welcomeTabIcon() const
|
||||
{
|
||||
static const QIcon icon(":/robomongo/icons/welcome_tab_icon.png");
|
||||
return icon;
|
||||
}
|
||||
|
||||
const QFont &GuiRegistry::font() const
|
||||
{
|
||||
QString family = AppRegistry::instance().settingsManager()->textFontFamily();
|
||||
|
||||
@@ -30,10 +30,7 @@ namespace Robomongo
|
||||
*/
|
||||
const QIcon& serverIcon() const;
|
||||
const QIcon& serverImportedIcon() const;
|
||||
const QIcon& serverPrimaryIcon() const;
|
||||
const QIcon& serverSecondaryIcon() const;
|
||||
const QIcon& replicaSetIcon() const;
|
||||
const QIcon& replicaSetOfflineIcon() const;
|
||||
const QIcon& saveIcon() const;
|
||||
const QIcon& openIcon() const;
|
||||
const QIcon& databaseIcon() const;
|
||||
@@ -42,9 +39,7 @@ namespace Robomongo
|
||||
const QIcon& userIcon() const;
|
||||
const QIcon& functionIcon() const;
|
||||
const QIcon& maximizeIcon() const;
|
||||
const QIcon& minimizeIcon() const;
|
||||
const QIcon& undockIcon() const;
|
||||
const QIcon& dockIcon() const;
|
||||
const QIcon& maximizeHighlightedIcon() const;
|
||||
const QIcon& textIcon() const;
|
||||
const QIcon& textHighlightedIcon() const;
|
||||
const QIcon& treeIcon() const;
|
||||
@@ -60,15 +55,11 @@ namespace Robomongo
|
||||
const QIcon& leftIcon() const;
|
||||
const QIcon& rightIcon() const;
|
||||
const QIcon& mongodbIcon() const;
|
||||
const QIcon& mongodbIconForMAC() const;
|
||||
const QIcon& connectIcon() const;
|
||||
const QIcon& executeIcon() const;
|
||||
const QIcon& stopIcon() const;
|
||||
const QIcon& exportIcon() const;
|
||||
const QIcon& importIcon() const;
|
||||
const QIcon& deleteIcon() const;
|
||||
const QIcon& deleteIconRed() const;
|
||||
const QIcon& deleteIconMouseHovered() const;
|
||||
const QIcon& mainWindowIcon() const;
|
||||
const QIcon& bsonObjectIcon() const;
|
||||
const QIcon& bsonArrayIcon() const;
|
||||
@@ -87,9 +78,6 @@ namespace Robomongo
|
||||
const QIcon& keyIcon() const;
|
||||
const QIcon& showIcon() const;
|
||||
const QIcon& hideIcon() const;
|
||||
const QIcon& plusIcon() const;
|
||||
const QIcon& minusIcon() const;
|
||||
const QIcon& welcomeTabIcon() const;
|
||||
|
||||
const QBrush& typeBrush() const;
|
||||
|
||||
|
||||
@@ -17,12 +17,6 @@
|
||||
#include <QStatusBar>
|
||||
#include <QHBoxLayout>
|
||||
#include <QSettings>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QUrl>
|
||||
#include <QTextDocument>
|
||||
|
||||
#include <mongo/logger/log_severity.h>
|
||||
#include "robomongo/core/settings/SettingsManager.h"
|
||||
@@ -36,20 +30,14 @@
|
||||
|
||||
#include "robomongo/gui/widgets/LogWidget.h"
|
||||
#include "robomongo/gui/widgets/explorer/ExplorerWidget.h"
|
||||
#include "robomongo/gui/widgets/explorer/ExplorerCollectionTreeItem.h"
|
||||
#include "robomongo/gui/widgets/explorer/ExplorerTreeWidget.h"
|
||||
#include "robomongo/gui/widgets/workarea/WorkAreaTabWidget.h"
|
||||
#include "robomongo/gui/widgets/workarea/QueryWidget.h"
|
||||
#include "robomongo/gui/widgets/workarea/QueryWidget.h"
|
||||
#include "robomongo/gui/widgets/workarea/WelcomeTab.h"
|
||||
#include "robomongo/gui/dialogs/ConnectionsDialog.h"
|
||||
#include "robomongo/gui/dialogs/AboutDialog.h"
|
||||
#include "robomongo/gui/dialogs/PreferencesDialog.h"
|
||||
#include "robomongo/gui/dialogs/ExportDialog.h"
|
||||
#include "robomongo/gui/GuiRegistry.h"
|
||||
#include "robomongo/gui/AppStyle.h"
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
void setToolBarIconSize(QToolBar *toolBar)
|
||||
@@ -80,32 +68,21 @@ namespace
|
||||
Robomongo::AppRegistry::instance().settingsManager()->save();
|
||||
}
|
||||
|
||||
void saveMinimizeToTraySettings(bool isMinimizingToTray)
|
||||
{
|
||||
Robomongo::AppRegistry::instance().settingsManager()->setMinimizeToTray(isMinimizingToTray);
|
||||
Robomongo::AppRegistry::instance().settingsManager()->save();
|
||||
}
|
||||
|
||||
void saveLineNumbers(bool showLineNumbers)
|
||||
{
|
||||
Robomongo::AppRegistry::instance().settingsManager()->setLineNumbers(showLineNumbers);
|
||||
Robomongo::AppRegistry::instance().settingsManager()->save();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
/* End of anonymous namespace */
|
||||
|
||||
}
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
/* -------------------------------- ConnectionMenu ---------------------------- */
|
||||
class ConnectionMenu : public QMenu
|
||||
{
|
||||
public:
|
||||
ConnectionMenu(QWidget *parent) : QMenu(parent) {}
|
||||
protected:
|
||||
virtual void keyPressEvent(QKeyEvent *event) override
|
||||
virtual void keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->key() == Qt::Key_F12) {
|
||||
hide();
|
||||
@@ -116,19 +93,12 @@ namespace Robomongo
|
||||
}
|
||||
};
|
||||
|
||||
/* -------------------------------- MainWindow --------------------------------- */
|
||||
MainWindow::MainWindow()
|
||||
: BaseClass(),
|
||||
_logDock(nullptr), _workArea(nullptr), _explorer(nullptr), _app(AppRegistry::instance().app()),
|
||||
_connectionsMenu(nullptr), _connectButton(nullptr), _viewMenu(nullptr), _toolbarsMenu(nullptr),
|
||||
_connectAction(nullptr), _openAction(nullptr), _saveAction(nullptr), _saveAsAction(nullptr),
|
||||
_executeAction(nullptr), _stopAction(nullptr), _orientationAction(nullptr), _execToolBar(nullptr),
|
||||
//_exportAction(nullptr), _importAction(nullptr), // Temporarily disabling export/import feature
|
||||
#if defined(Q_OS_WIN)
|
||||
_trayIcon(nullptr),
|
||||
#endif
|
||||
_allowExit(false)
|
||||
{
|
||||
_app(AppRegistry::instance().app()),
|
||||
_workArea(NULL),
|
||||
_connectionsMenu(NULL)
|
||||
{
|
||||
QColor background = palette().window().color();
|
||||
QString controlKey = "Ctrl";
|
||||
|
||||
@@ -165,7 +135,7 @@ namespace Robomongo
|
||||
// Exit action
|
||||
QAction *exitAction = new QAction("&Exit", this);
|
||||
exitAction->setShortcuts(QKeySequence::Quit);
|
||||
VERIFY(connect(exitAction, SIGNAL(triggered()), this, SLOT(exit())));
|
||||
VERIFY(connect(exitAction, SIGNAL(triggered()), this, SLOT(close())));
|
||||
|
||||
// Connect action
|
||||
_connectAction = new QAction("&Connect...", this);
|
||||
@@ -196,26 +166,6 @@ namespace Robomongo
|
||||
QWidgetAction *connectButtonAction = new QWidgetAction(this);
|
||||
connectButtonAction->setDefaultWidget(_connectButton);
|
||||
|
||||
// Tray icon
|
||||
#if defined(Q_OS_WIN)
|
||||
_trayIcon = new QSystemTrayIcon(GuiRegistry::instance().mainWindowIcon());
|
||||
VERIFY(connect(_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
|
||||
this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason))));
|
||||
|
||||
auto trayMinimizeAction = new QAction("Minimize to Tray", _trayIcon);
|
||||
VERIFY(connect(trayMinimizeAction, SIGNAL(triggered()), this, SLOT(toggleMinimize())));
|
||||
|
||||
auto trayExitAction = new QAction("Exit", _trayIcon);
|
||||
VERIFY(connect(trayExitAction, SIGNAL(triggered()), this, SLOT(exit())));
|
||||
|
||||
auto contextMenu = new QMenu();
|
||||
contextMenu->addAction(trayMinimizeAction);
|
||||
contextMenu->addSeparator();
|
||||
contextMenu->addAction(trayExitAction);
|
||||
|
||||
_trayIcon->setContextMenu(contextMenu);
|
||||
#endif
|
||||
|
||||
// Orientation action
|
||||
_orientationAction = new QAction("&Rotate", this);
|
||||
_orientationAction->setShortcut(Qt::Key_F10);
|
||||
@@ -227,7 +177,7 @@ namespace Robomongo
|
||||
ViewMode viewMode = AppRegistry::instance().settingsManager()->viewMode();
|
||||
|
||||
// Text mode action
|
||||
auto textModeAction = new QAction("&Text Mode", this);
|
||||
QAction *textModeAction = new QAction("&Text Mode", this);
|
||||
textModeAction->setShortcut(Qt::Key_F4);
|
||||
textModeAction->setIcon(GuiRegistry::instance().textHighlightedIcon());
|
||||
textModeAction->setToolTip("Show current tab in text mode, and make this mode default for all subsequent queries <b>(F4)</b>");
|
||||
@@ -432,20 +382,6 @@ namespace Robomongo
|
||||
VERIFY(connect(autoExec, SIGNAL(triggered()), this, SLOT(toggleAutoExec())));
|
||||
optionsMenu->addAction(autoExec);
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
QAction *minimizeTray = new QAction("Close button should minimize to system tray");
|
||||
minimizeTray->setCheckable(true);
|
||||
minimizeTray->setChecked(AppRegistry::instance().settingsManager()->minimizeToTray());
|
||||
VERIFY(connect(minimizeTray, SIGNAL(triggered()), this, SLOT(toggleMinimizeToTray())));
|
||||
optionsMenu->addAction(minimizeTray);
|
||||
#endif
|
||||
|
||||
auto *checkUpdates = new QAction(tr("Check for updates"), this);
|
||||
checkUpdates->setCheckable(true);
|
||||
checkUpdates->setChecked(AppRegistry::instance().settingsManager()->checkForUpdates());
|
||||
VERIFY(connect(checkUpdates, SIGNAL(triggered()), this, SLOT(toggleCheckUpdates())));
|
||||
optionsMenu->addAction(checkUpdates);
|
||||
|
||||
QAction *preferencesAction = new QAction("Preferences", this);
|
||||
VERIFY(connect(preferencesAction, SIGNAL(triggered()), this, SLOT(openPreferences())));
|
||||
preferencesAction->setVisible(false);
|
||||
@@ -498,12 +434,6 @@ namespace Robomongo
|
||||
duplicateAction->setVisible(true);
|
||||
VERIFY(connect(duplicateAction, SIGNAL(triggered()), SLOT(duplicateTab())));
|
||||
|
||||
// Open welcome tab action
|
||||
auto openWelcomeTabAction = new QAction("Open/Refresh Welcome Tab", this);
|
||||
openWelcomeTabAction->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_W);
|
||||
openWelcomeTabAction->setVisible(true);
|
||||
VERIFY(connect(openWelcomeTabAction, SIGNAL(triggered()), SLOT(openWelcomeTab())));
|
||||
|
||||
// Window menu
|
||||
QMenu *windowMenu = menuBar()->addMenu("Window");
|
||||
//minimize
|
||||
@@ -515,10 +445,8 @@ namespace Robomongo
|
||||
windowMenu->addSeparator();
|
||||
windowMenu->addAction(reloadAction);
|
||||
windowMenu->addAction(duplicateAction);
|
||||
windowMenu->addSeparator();
|
||||
windowMenu->addAction(openWelcomeTabAction);
|
||||
|
||||
auto toolbarsSettings = AppRegistry::instance().settingsManager()->toolbars();
|
||||
SettingsManager::ToolbarSettingsContainerType toolbarsSettings = AppRegistry::instance().settingsManager()->toolbars();
|
||||
|
||||
/*** About menu ***/
|
||||
|
||||
@@ -562,70 +490,16 @@ namespace Robomongo
|
||||
setToolBarIconSize(_execToolBar);
|
||||
addToolBar(_execToolBar);
|
||||
|
||||
_updateLabel = new QLabel;
|
||||
_updateLabel->setWordWrap(true);
|
||||
_updateLabel->setOpenExternalLinks(true);
|
||||
_updateLabel->setTextFormat(Qt::TextFormat::RichText);
|
||||
_updateLabel->setIndent(_updateLabel->fontMetrics().width("T"));
|
||||
|
||||
_closeButton = new QPushButton;
|
||||
_closeButton->setIcon(QIcon(":/robomongo/icons/close_hover_16x16.png"));
|
||||
_closeButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum);
|
||||
_closeButton->setMouseTracking(true);
|
||||
_closeButton->setAttribute(Qt::WA_Hover);
|
||||
_closeButton->installEventFilter(this);
|
||||
VERIFY(connect(_closeButton, SIGNAL(clicked()), this, SLOT(on_closeButton_clicked())));
|
||||
|
||||
auto updateBarLay = new QHBoxLayout;
|
||||
updateBarLay->addWidget(_updateLabel);
|
||||
updateBarLay->addWidget(_closeButton, Qt::AlignRight);
|
||||
updateBarLay->setSpacing(0);
|
||||
updateBarLay->setMargin(0);
|
||||
|
||||
auto updateBarWid = new QWidget;
|
||||
updateBarWid->setLayout(updateBarLay);
|
||||
|
||||
_updateBar = new QToolBar("Updates Toolbar");
|
||||
_updateBar->addWidget(updateBarWid);
|
||||
_updateBar->setStyleSheet("background-color: #b3e0ff; border: none;"); // blue
|
||||
addToolBarBreak();
|
||||
addToolBar(_updateBar);
|
||||
_updateBar->setHidden(true);
|
||||
_updateBar->setMovable(false);
|
||||
|
||||
_toolbarsMenu->addAction(_execToolBar->toggleViewAction());
|
||||
VERIFY(connect(_execToolBar->toggleViewAction(), SIGNAL(triggered(bool)), this, SLOT(onExecToolbarVisibilityChanged(bool))));
|
||||
|
||||
/* --- Temporarily disabling export/import feature
|
||||
// Export/Import Toolbar
|
||||
auto expImpToolBar = new QToolBar(tr("Export/Import Toolbar"), this);
|
||||
expImpToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
expImpToolBar->setMovable(false);
|
||||
// Add export action
|
||||
_exportAction = new QAction(this);
|
||||
_exportAction->setData("Export");
|
||||
_exportAction->setIcon(GuiRegistry::instance().exportIcon());
|
||||
_exportAction->setDisabled(true);
|
||||
VERIFY(connect(_exportAction, SIGNAL(triggered()), this, SLOT(openExportDialog())));
|
||||
addToolBar(expImpToolBar);
|
||||
expImpToolBar->addAction(_exportAction);
|
||||
// Add import action
|
||||
_importAction = new QAction(this);
|
||||
_importAction->setData("Import");
|
||||
_importAction->setIcon(GuiRegistry::instance().importIcon());
|
||||
_importAction->setDisabled(true);
|
||||
addToolBar(expImpToolBar);
|
||||
expImpToolBar->addAction(_importAction);
|
||||
*/
|
||||
|
||||
createTabs();
|
||||
createStatusBar();
|
||||
setWindowTitle("Robomongo 1.0.3");
|
||||
setWindowTitle(PROJECT_NAME_TITLE " " PROJECT_VERSION);
|
||||
setWindowIcon(GuiRegistry::instance().mainWindowIcon());
|
||||
|
||||
QTimer::singleShot(0, this, SLOT(manageConnections()));
|
||||
QTimer::singleShot(0, this, SLOT(manageConnections()));
|
||||
updateMenus();
|
||||
_updateMenusAtStart = false;
|
||||
|
||||
AppRegistry::instance().bus()->subscribe(this, ConnectionFailedEvent::Type);
|
||||
AppRegistry::instance().bus()->subscribe(this, ScriptExecutedEvent::Type);
|
||||
@@ -633,21 +507,7 @@ namespace Robomongo
|
||||
AppRegistry::instance().bus()->subscribe(this, QueryWidgetUpdatedEvent::Type);
|
||||
AppRegistry::instance().bus()->subscribe(this, OperationFailedEvent::Type);
|
||||
|
||||
restoreWindowSettings();
|
||||
|
||||
// Catch application windows focus changes
|
||||
VERIFY(connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)), this, SLOT(on_focusChanged())));
|
||||
|
||||
_networkAccessManager = new QNetworkAccessManager;
|
||||
VERIFY(connect(_networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(on_networkReply(QNetworkReply*))));
|
||||
|
||||
// First check for updates 30 secs after program start
|
||||
QTimer::singleShot(30000, this, SLOT(checkUpdates())); // 30000 for 30secs
|
||||
|
||||
// Check for updates every 1 hour
|
||||
auto timer = new QTimer(this);
|
||||
VERIFY(connect(timer, SIGNAL(timeout()), this, SLOT(checkUpdates())));
|
||||
timer->start(3600000); // 1 hour = (3600000 msec = 60 * 60 * 1000 msec)
|
||||
restoreWindowsSettings();
|
||||
}
|
||||
|
||||
void MainWindow::createStylesMenu()
|
||||
@@ -709,26 +569,22 @@ namespace Robomongo
|
||||
AppRegistry::instance().settingsManager()->save();
|
||||
}
|
||||
|
||||
void MainWindow::exit()
|
||||
void MainWindow::restoreWindowsSettings()
|
||||
{
|
||||
_allowExit = true;
|
||||
close();
|
||||
}
|
||||
|
||||
void MainWindow::restoreWindowSettings()
|
||||
{
|
||||
QSettings settings("3T", "Robomongo");
|
||||
QSettings settings("Paralect", "Robomongo");
|
||||
// Restore settings if registery key exists, otherwise resize as app started for the first time.
|
||||
if (settings.contains("MainWindow/geometry"))
|
||||
{
|
||||
restoreGeometry(settings.value("MainWindow/geometry").toByteArray());
|
||||
restoreState(settings.value("MainWindow/windowState").toByteArray());
|
||||
settings.setValue("windowState", saveState());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Resize main window. We are trying to keep it "almost" maximized.
|
||||
QRect screenGeometry = QApplication::desktop()->availableGeometry();
|
||||
int horizontalMargin = static_cast<int>(screenGeometry.width() * 0.1);
|
||||
int verticalMargin = static_cast<int>(screenGeometry.height() * 0.1);
|
||||
int horizontalMargin = (int)(screenGeometry.width() * 0.1); // todo: use C++ static cast instead of C-style cast
|
||||
int verticalMargin = (int)(screenGeometry.height() * 0.1);
|
||||
int _width = screenGeometry.width() - horizontalMargin;
|
||||
int _height = screenGeometry.height() - verticalMargin;
|
||||
resize(QSize(_width, _height));
|
||||
@@ -740,31 +596,11 @@ namespace Robomongo
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::saveWindowSettings() const
|
||||
void MainWindow::saveWindowsSettings() const
|
||||
{
|
||||
QSettings settings("3T", "Robomongo");
|
||||
QSettings settings("Paralect", "Robomongo");
|
||||
settings.setValue("MainWindow/geometry", saveGeometry());
|
||||
}
|
||||
|
||||
void MainWindow::adjustUpdatesBarHeight()
|
||||
{
|
||||
if (!AppRegistry::instance().settingsManager()->checkForUpdates() || !_updateBar->isVisible())
|
||||
return;
|
||||
|
||||
QTextDocument doc;
|
||||
doc.setHtml(_updateLabel->text());
|
||||
int const strWidth = _updateLabel->fontMetrics().width(doc.toPlainText());
|
||||
int const lineHeight = _updateLabel->fontMetrics().height();
|
||||
int const widthForUpdateStr = width() - _closeButton->width();
|
||||
|
||||
if (0 == widthForUpdateStr)
|
||||
return;
|
||||
|
||||
#ifdef __APPLE__
|
||||
_updateLabel->setFixedHeight((strWidth / widthForUpdateStr + 1) * lineHeight * 1.3);
|
||||
#else
|
||||
_updateLabel->setFixedHeight((strWidth / widthForUpdateStr + 1) * lineHeight);
|
||||
#endif
|
||||
settings.setValue("MainWindow/windowState", saveState());
|
||||
}
|
||||
|
||||
void MainWindow::open()
|
||||
@@ -773,14 +609,12 @@ namespace Robomongo
|
||||
if (wid) {
|
||||
wid->openFile();
|
||||
}
|
||||
else { // todo: currently this case not handled properly, since "Open" button is
|
||||
// disabled when no tabs exist
|
||||
auto connectionsCopy = AppRegistry::instance().settingsManager()->connections();
|
||||
if (connectionsCopy.size() == 1) {
|
||||
else {
|
||||
SettingsManager::ConnectionSettingsContainerType connections = AppRegistry::instance().settingsManager()->connections();
|
||||
if (connections.size() == 1) {
|
||||
ScriptInfo inf = ScriptInfo(QString());
|
||||
if (inf.loadFromFile()) {
|
||||
// todo: for now do not open new shell
|
||||
_app->openShell(nullptr, connectionsCopy.at(0), inf);
|
||||
_app->openShell(connections.at(0), inf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -802,6 +636,16 @@ namespace Robomongo
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->key() == Qt::Key_F12) {
|
||||
_connectButton->showMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
BaseClass::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void MainWindow::updateConnectionsMenu()
|
||||
{
|
||||
_connectionsMenu->clear();
|
||||
@@ -833,17 +677,8 @@ namespace Robomongo
|
||||
_connectionsMenu->addAction(connectAction);
|
||||
}
|
||||
|
||||
WelcomeTab* MainWindow::getWelcomeTab()
|
||||
{
|
||||
return _workArea->getWelcomeTab();
|
||||
}
|
||||
|
||||
void MainWindow::manageConnections()
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
_trayIcon->hide(); // hide the tray icon so the main window can't be hidden behind the connections dialog
|
||||
#endif
|
||||
|
||||
static bool checkForImported = true;
|
||||
ConnectionsDialog dialog(AppRegistry::instance().settingsManager(), checkForImported, this);
|
||||
int result = dialog.exec();
|
||||
@@ -875,10 +710,6 @@ namespace Robomongo
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
_trayIcon->show(); // show the tray icon once the connections dialog is gone
|
||||
#endif
|
||||
|
||||
// on linux focus is lost - we need to activate main window back
|
||||
activateWindow();
|
||||
}
|
||||
@@ -944,13 +775,6 @@ namespace Robomongo
|
||||
saveAutoExec(send->isChecked());
|
||||
}
|
||||
|
||||
void MainWindow::toggleCheckUpdates()
|
||||
{
|
||||
auto action = qobject_cast<QAction*>(sender());
|
||||
AppRegistry::instance().settingsManager()->setCheckForUpdates(action->isChecked());
|
||||
AppRegistry::instance().settingsManager()->save();
|
||||
}
|
||||
|
||||
void MainWindow::toggleLineNumbers()
|
||||
{
|
||||
QAction *send = qobject_cast<QAction*>(sender());
|
||||
@@ -1020,24 +844,6 @@ namespace Robomongo
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::openWelcomeTab()
|
||||
{
|
||||
_workArea->openWelcomeTab();
|
||||
}
|
||||
|
||||
/* --- Temporarily disabling export/import feature
|
||||
void MainWindow::openExportDialog()
|
||||
{
|
||||
auto selectedItem = dynamic_cast<ExplorerCollectionTreeItem*>(_explorer->getSelectedTreeItem());
|
||||
auto dbName = QString::fromStdString(selectedItem->collection()->database()->name());
|
||||
auto collName = QString::fromStdString(selectedItem->collection()->name());
|
||||
|
||||
auto dialog = new ExportDialog(dbName, collName, this);
|
||||
dialog->show(); // show it mode-less so that user can perform multiple simultaneous exports
|
||||
}
|
||||
*/
|
||||
|
||||
void MainWindow::setDefaultUuidEncoding()
|
||||
{
|
||||
AppRegistry::instance().settingsManager()->setUuidEncoding(DefaultEncoding);
|
||||
@@ -1132,6 +938,7 @@ namespace Robomongo
|
||||
if (event->connectionType != ConnectionPrimary)
|
||||
return;
|
||||
|
||||
|
||||
// Very temporary solution to prevent multiple connection error messages
|
||||
// from both SshTunnelWorker and MongoWorker
|
||||
static int lastServerHandle = -1;
|
||||
@@ -1139,7 +946,7 @@ namespace Robomongo
|
||||
return;
|
||||
|
||||
lastServerHandle = event->serverHandle;
|
||||
QMessageBox::critical(this, "Error", QtUtils::toQString(event->message));
|
||||
QMessageBox::information(this, "Error", QtUtils::toQString(event->message));
|
||||
}
|
||||
|
||||
void MainWindow::handle(ScriptExecutingEvent *)
|
||||
@@ -1160,78 +967,13 @@ namespace Robomongo
|
||||
ss << event->userFriendlyErrorMessage << std::endl << std::endl
|
||||
<< "Error:" << std::endl << event->technicalErrorMessage;
|
||||
|
||||
QMessageBox::critical(NULL, "Operation failed", QtUtils::toQString(ss.str()));
|
||||
}
|
||||
|
||||
void MainWindow::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->key() == Qt::Key_F12) {
|
||||
_connectButton->showMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
BaseClass::keyPressEvent(event);
|
||||
QMessageBox::information(NULL, "Operation failed", QtUtils::toQString(ss.str()));
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
saveWindowSettings();
|
||||
#if defined(Q_OS_WIN)
|
||||
if (AppRegistry::instance().settingsManager()->minimizeToTray() && !_allowExit) {
|
||||
event->ignore();
|
||||
hide(); // hide the window because it can be reopened with the tray icon
|
||||
}
|
||||
else {
|
||||
if (_trayIcon->isVisible())
|
||||
_trayIcon->hide();
|
||||
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
#else
|
||||
saveWindowsSettings();
|
||||
QMainWindow::closeEvent(event);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::hideEvent(QHideEvent *event)
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
if (_trayIcon->contextMenu()->actions().size() > 0 && isHidden()) {
|
||||
_trayIcon->contextMenu()->actions().at(0)->setText("Show Robomongo");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::showEvent(QShowEvent *event)
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
if (_trayIcon->contextMenu()->actions().size() > 0) {
|
||||
_trayIcon->contextMenu()->actions().at(0)->setText("Minimize to Tray");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MainWindow::eventFilter(QObject *target, QEvent *event)
|
||||
{
|
||||
auto closeUpdatesBarButton = qobject_cast<QPushButton*>(target);
|
||||
if (!closeUpdatesBarButton)
|
||||
return false;
|
||||
|
||||
if (event->type() == QEvent::HoverEnter) {
|
||||
closeUpdatesBarButton->setIcon(QIcon(":/robomongo/icons/close_hover_16x16_original.png"));
|
||||
return true;
|
||||
}
|
||||
else if (event->type() == QEvent::HoverLeave) {
|
||||
closeUpdatesBarButton->setIcon(QIcon(":/robomongo/icons/close_hover_16x16.png"));
|
||||
return true;
|
||||
}
|
||||
|
||||
return QWidget::eventFilter(target, event);
|
||||
}
|
||||
|
||||
void MainWindow::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
QMainWindow::resizeEvent(event);
|
||||
adjustUpdatesBarHeight();
|
||||
}
|
||||
|
||||
void MainWindow::handle(QueryWidgetUpdatedEvent *event)
|
||||
@@ -1241,14 +983,14 @@ namespace Robomongo
|
||||
|
||||
void MainWindow::createDatabaseExplorer()
|
||||
{
|
||||
_explorer = new ExplorerWidget(this);
|
||||
AppRegistry::instance().bus()->subscribe(_explorer, ConnectingEvent::Type);
|
||||
AppRegistry::instance().bus()->subscribe(_explorer, ConnectionFailedEvent::Type);
|
||||
AppRegistry::instance().bus()->subscribe(_explorer, ConnectionEstablishedEvent::Type);
|
||||
ExplorerWidget *explorer = new ExplorerWidget(this);
|
||||
AppRegistry::instance().bus()->subscribe(explorer, ConnectingEvent::Type);
|
||||
AppRegistry::instance().bus()->subscribe(explorer, ConnectionFailedEvent::Type);
|
||||
AppRegistry::instance().bus()->subscribe(explorer, ConnectionEstablishedEvent::Type);
|
||||
|
||||
QDockWidget *explorerDock = new QDockWidget(tr("Database Explorer"));
|
||||
explorerDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
||||
explorerDock->setWidget(_explorer);
|
||||
explorerDock->setWidget(explorer);
|
||||
explorerDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
||||
|
||||
QWidget *titleWidget = new QWidget(this); // this lines simply remove
|
||||
@@ -1275,7 +1017,7 @@ namespace Robomongo
|
||||
_logDock = new QDockWidget(tr("Logs"));
|
||||
_logDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea);
|
||||
_logDock->setWidget(log);
|
||||
_logDock->setFeatures(QDockWidget::DockWidgetClosable);
|
||||
_logDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
||||
_logDock->setVisible(false);
|
||||
|
||||
QAction *action = _logDock->toggleViewAction();
|
||||
@@ -1291,20 +1033,8 @@ namespace Robomongo
|
||||
|
||||
void MainWindow::updateMenus()
|
||||
{
|
||||
if (!_workArea)
|
||||
return;
|
||||
|
||||
bool isEnable = false;
|
||||
if (_updateMenusAtStart)
|
||||
isEnable = false;
|
||||
else {
|
||||
if (getWelcomeTab() && getWelcomeTab()->isVisible())
|
||||
isEnable = false;
|
||||
else if (_workArea->count() == 0)
|
||||
isEnable = false;
|
||||
else
|
||||
isEnable = true;
|
||||
}
|
||||
int contTab = _workArea->count();
|
||||
bool isEnable = _workArea && contTab > 0;
|
||||
|
||||
_execToolBar->setEnabled(isEnable);
|
||||
_openAction->setEnabled(isEnable);
|
||||
@@ -1317,7 +1047,6 @@ namespace Robomongo
|
||||
_workArea = new WorkAreaTabWidget(this);
|
||||
AppRegistry::instance().bus()->subscribe(_workArea, OpeningShellEvent::Type);
|
||||
VERIFY(connect(_workArea, SIGNAL(currentChanged(int)), this, SLOT(updateMenus())));
|
||||
VERIFY(connect(_workArea, SIGNAL(currentChanged(int)), this, SLOT(on_tabChange())));
|
||||
|
||||
QHBoxLayout *hlayout = new QHBoxLayout;
|
||||
hlayout->setContentsMargins(0, 3, 0, 0);
|
||||
@@ -1351,104 +1080,4 @@ namespace Robomongo
|
||||
AppRegistry::instance().settingsManager()->setToolbarSettings("explorer", isVisible);
|
||||
AppRegistry::instance().settingsManager()->save();
|
||||
}
|
||||
|
||||
/* --- Temporarily disabling export/import feature
|
||||
void MainWindow::onExplorerItemSelected(QTreeWidgetItem *selectedItem)
|
||||
{
|
||||
auto collectionItem = dynamic_cast<ExplorerCollectionTreeItem*>(selectedItem);
|
||||
if (collectionItem) {
|
||||
_exportAction->setEnabled(true);
|
||||
}
|
||||
else {
|
||||
_exportAction->setDisabled(true);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void MainWindow::on_tabChange()
|
||||
{
|
||||
auto activeTab = dynamic_cast<QueryWidget*>(_workArea->currentWidget());
|
||||
if (activeTab) {
|
||||
activeTab->bringDockToFront();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::toggleMinimize()
|
||||
{
|
||||
if (isHidden()) {
|
||||
show();
|
||||
}
|
||||
else {
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason)
|
||||
{
|
||||
if (QSystemTrayIcon::DoubleClick == reason && isHidden()) {
|
||||
show();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::toggleMinimizeToTray()
|
||||
{
|
||||
QAction *send = qobject_cast<QAction*>(sender());
|
||||
saveMinimizeToTraySettings(send->isChecked());
|
||||
}
|
||||
|
||||
void MainWindow::on_focusChanged()
|
||||
{
|
||||
// If focus is on floating output window, make it's parent (which is a QueryWidget tab) as active tab
|
||||
auto const activeDock = dynamic_cast<QueryWidget::CustomDockWidget*>(qApp->activeWindow());
|
||||
if (activeDock) {
|
||||
_workArea->setCurrentWidget(activeDock->getParentQueryWidget());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_networkReply(QNetworkReply* reply)
|
||||
{
|
||||
QString str(QUrl::fromPercentEncoding(reply->readAll()));
|
||||
|
||||
if ("NO-UPDATES-ANNOUNCED.\n" == str || reply->error() != QNetworkReply::NoError || str.isEmpty()) {
|
||||
_updateLabel->setText("");
|
||||
_updateBar->setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
str.replace('+', ' ');
|
||||
str.remove("Update,");
|
||||
|
||||
_updateLabel->setText(str);
|
||||
_updateBar->setVisible(true);
|
||||
adjustUpdatesBarHeight();
|
||||
}
|
||||
|
||||
void MainWindow::on_closeButton_clicked()
|
||||
{
|
||||
_updateBar->setVisible(false);
|
||||
}
|
||||
|
||||
void MainWindow::checkUpdates()
|
||||
{
|
||||
if (!Robomongo::AppRegistry::instance().settingsManager()->checkForUpdates())
|
||||
return;
|
||||
|
||||
#ifdef _WIN32
|
||||
QString const OS = "win";
|
||||
#elif __APPLE__
|
||||
QString const OS = "osx";
|
||||
#elif __linux__
|
||||
QString const OS = "linux";
|
||||
#else
|
||||
QString const OS = "unknown";
|
||||
#endif
|
||||
|
||||
// softwareId=8: Robomongo product ID
|
||||
QUrl url("http://updates.3tsoftwarelabs.com/check.php?os=" + OS + "&softwareId=8&softwareVersion=" +
|
||||
QString(PROJECT_VERSION) + "&licenseInfo=FREE&setup=" +
|
||||
AppRegistry::instance().settingsManager()->anonymousID() + "¬ify=true#");
|
||||
|
||||
_networkAccessManager->get(QNetworkRequest(url));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QSystemTrayIcon>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLabel;
|
||||
class QToolBar;
|
||||
class QDockWidget;
|
||||
class QToolButton;
|
||||
class QPushButton;
|
||||
class QTreeWidgetItem;
|
||||
class QNetworkReply;
|
||||
class QNetworkAccessManager;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Robomongo
|
||||
@@ -25,8 +19,6 @@ namespace Robomongo
|
||||
class WorkAreaTabWidget;
|
||||
class ConnectionMenu;
|
||||
class App;
|
||||
class ExplorerWidget;
|
||||
class WelcomeTab;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
@@ -35,8 +27,7 @@ namespace Robomongo
|
||||
public:
|
||||
typedef QMainWindow BaseClass;
|
||||
MainWindow();
|
||||
|
||||
WelcomeTab* getWelcomeTab();
|
||||
void keyPressEvent(QKeyEvent *event);
|
||||
|
||||
public Q_SLOTS:
|
||||
void manageConnections();
|
||||
@@ -60,7 +51,6 @@ namespace Robomongo
|
||||
void save();
|
||||
void saveAs();
|
||||
void changeStyle(QAction *);
|
||||
void exit();
|
||||
|
||||
void setDefaultUuidEncoding();
|
||||
void setJavaUuidEncoding();
|
||||
@@ -81,62 +71,32 @@ namespace Robomongo
|
||||
void handle(OperationFailedEvent *event);
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
bool eventFilter(QObject *target, QEvent *event) override;
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
||||
private Q_SLOTS:
|
||||
void updateMenus();
|
||||
void setUtcTimeZone();
|
||||
void setLocalTimeZone();
|
||||
void openPreferences();
|
||||
void openWelcomeTab();
|
||||
|
||||
// Temporarily disabling export/import feature
|
||||
//void openExportDialog();
|
||||
|
||||
|
||||
void onConnectToolbarVisibilityChanged(bool isVisisble);
|
||||
void onOpenSaveToolbarVisibilityChanged(bool isVisisble);
|
||||
void onExecToolbarVisibilityChanged(bool isVisisble);
|
||||
void onExplorerVisibilityChanged(bool isVisisble);
|
||||
|
||||
// Temporarily disabling export/import feature
|
||||
//void onExplorerItemSelected(QTreeWidgetItem *selectedItem);
|
||||
|
||||
void on_tabChange();
|
||||
|
||||
void toggleMinimize();
|
||||
void trayActivated(QSystemTrayIcon::ActivationReason reason);
|
||||
void toggleMinimizeToTray();
|
||||
|
||||
// On application focus changes
|
||||
void on_focusChanged();
|
||||
|
||||
void on_networkReply(QNetworkReply* reply);
|
||||
void on_closeButton_clicked();
|
||||
|
||||
void checkUpdates();
|
||||
void toggleCheckUpdates();
|
||||
|
||||
private:
|
||||
void updateConnectionsMenu();
|
||||
void createDatabaseExplorer();
|
||||
void createTabs();
|
||||
void createStylesMenu();
|
||||
void createStatusBar();
|
||||
void restoreWindowSettings();
|
||||
void saveWindowSettings() const;
|
||||
void adjustUpdatesBarHeight();
|
||||
void restoreWindowsSettings();
|
||||
void saveWindowsSettings() const;
|
||||
|
||||
QDockWidget *_logDock;
|
||||
|
||||
WorkAreaTabWidget *_workArea;
|
||||
|
||||
ExplorerWidget* _explorer;
|
||||
|
||||
App *_app;
|
||||
|
||||
ConnectionMenu *_connectionsMenu;
|
||||
@@ -144,34 +104,14 @@ namespace Robomongo
|
||||
QMenu *_viewMenu;
|
||||
QMenu *_toolbarsMenu;
|
||||
QAction *_connectAction;
|
||||
// Open/Save tool bar
|
||||
QAction *_openAction;
|
||||
QAction *_saveAction;
|
||||
QAction *_saveAsAction;
|
||||
// Execution tool bar
|
||||
QAction *_executeAction;
|
||||
QAction *_stopAction;
|
||||
QAction *_orientationAction;
|
||||
QToolBar *_execToolBar;
|
||||
QToolBar *_updateBar;
|
||||
QLabel *_updateLabel;
|
||||
QPushButton* _closeButton;
|
||||
|
||||
QNetworkAccessManager *_networkAccessManager;
|
||||
|
||||
// Temporarily disabling export/import feature
|
||||
/*
|
||||
// Export/import tool bar
|
||||
QAction *_exportAction;
|
||||
QAction *_importAction;
|
||||
*/
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
QSystemTrayIcon *_trayIcon;
|
||||
#endif
|
||||
|
||||
bool _allowExit;
|
||||
bool _updateMenusAtStart = true;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QTabWidget>
|
||||
#include <QTextBrowser>
|
||||
#include <QFile>
|
||||
|
||||
#include "robomongo/gui/GuiRegistry.h"
|
||||
#include "robomongo/core/utils/QtUtils.h"
|
||||
@@ -18,11 +15,11 @@ namespace
|
||||
"Shell-centric MongoDB management tool."
|
||||
"<br/>"
|
||||
"<br/>"
|
||||
"Visit " PROJECT_NAME_TITLE " website: <a href=\"https://" PROJECT_DOMAIN "\">" PROJECT_DOMAIN "</a> <br/>"
|
||||
"Visit " PROJECT_NAME_TITLE " website: <a href=\"http://" PROJECT_DOMAIN "\">" PROJECT_DOMAIN "</a> <br/>"
|
||||
"<br/>"
|
||||
"<a href=\"https://" PROJECT_GITHUB_ISSUES "\">Submit</a> issues/proposals on GitHub. <br/>"
|
||||
"<a href=\"https://" PROJECT_GITHUB_FORK "\">Fork</a> project or <a href=\"https://" PROJECT_GITHUB_ISSUES "\">submit</a> issues/proposals on GitHub. <br/>"
|
||||
"<br/>"
|
||||
"Copyright 2014-2017 <a href= " PROJECT_COMPANYNAME_DOMAIN " >" PROJECT_COMPANYNAME "</a>. All rights reserved.<br/>"
|
||||
"Copyright 2013-2016 <a href=\"http:// " PROJECT_COMPANYNAME_DOMAIN "\">" PROJECT_COMPANYNAME "</a>. All rights reserved.<br/>"
|
||||
"<br/>"
|
||||
"The program is provided AS IS with NO WARRANTY OF ANY KIND, "
|
||||
"INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A "
|
||||
@@ -40,57 +37,30 @@ namespace Robomongo
|
||||
AboutDialog::AboutDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setWindowTitle("About " PROJECT_NAME_TITLE);
|
||||
setWindowIcon(GuiRegistry::instance().mainWindowIcon());
|
||||
|
||||
//// About tab
|
||||
auto aboutTab = new QWidget;
|
||||
aboutTab->setWindowIcon(GuiRegistry::instance().mainWindowIcon());
|
||||
aboutTab->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
auto layout = new QGridLayout(this);
|
||||
setWindowTitle("About " PROJECT_NAME_TITLE);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
QGridLayout *layout = new QGridLayout(this);
|
||||
layout->setSizeConstraint(QLayout::SetFixedSize);
|
||||
|
||||
auto copyRightLabel = new QLabel(description);
|
||||
QLabel *copyRightLabel = new QLabel(description);
|
||||
copyRightLabel->setWordWrap(true);
|
||||
copyRightLabel->setOpenExternalLinks(true);
|
||||
copyRightLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
|
||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
|
||||
QPushButton *closeButton = buttonBox->button(QDialogButtonBox::Close);
|
||||
buttonBox->addButton(closeButton, QDialogButtonBox::ButtonRole(QDialogButtonBox::RejectRole | QDialogButtonBox::AcceptRole));
|
||||
VERIFY(connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())));
|
||||
|
||||
QIcon icon = GuiRegistry::instance().mainWindowIcon();
|
||||
QPixmap iconPixmap = icon.pixmap(128, 128);
|
||||
|
||||
auto logoLabel = new QLabel;
|
||||
QLabel *logoLabel = new QLabel;
|
||||
logoLabel->setPixmap(iconPixmap);
|
||||
layout->addWidget(logoLabel, 0, 0, 1, 1);
|
||||
layout->addWidget(logoLabel , 0, 0, 1, 1);
|
||||
layout->addWidget(copyRightLabel, 0, 1, 4, 4);
|
||||
aboutTab->setLayout(layout);
|
||||
|
||||
//// License Agreement tab
|
||||
auto licenseTab = new QWidget;
|
||||
auto textBrowser = new QTextBrowser;
|
||||
textBrowser->setOpenExternalLinks(true);
|
||||
textBrowser->setOpenLinks(true);
|
||||
QFile file(":gnu_gpl3_license.html");
|
||||
if (file.open(QFile::ReadOnly | QFile::Text))
|
||||
textBrowser->setText(file.readAll());
|
||||
|
||||
auto licenseTabLay = new QVBoxLayout;
|
||||
licenseTabLay->addWidget(textBrowser);
|
||||
licenseTab->setLayout(licenseTabLay);
|
||||
|
||||
//// Button box
|
||||
auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
|
||||
QPushButton *closeButton = buttonBox->button(QDialogButtonBox::Close);
|
||||
buttonBox->addButton(closeButton, QDialogButtonBox::ButtonRole(QDialogButtonBox::RejectRole |
|
||||
QDialogButtonBox::AcceptRole));
|
||||
VERIFY(connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())));
|
||||
|
||||
//// Main layout
|
||||
auto tabWidget = new QTabWidget;
|
||||
tabWidget->addTab(aboutTab, "About");
|
||||
tabWidget->addTab(licenseTab, "License Agreement");
|
||||
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
mainLayout->addWidget(tabWidget);
|
||||
mainLayout->addWidget(buttonBox);
|
||||
setLayout(mainLayout);
|
||||
layout->addWidget(buttonBox, 4, 0, 1, 5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,25 +3,9 @@
|
||||
#include <QLabel>
|
||||
#include <QGridLayout>
|
||||
#include <QLineEdit>
|
||||
/* --- Disabling unfinished export URI connection string feature
|
||||
#include <QPushButton>
|
||||
#include <QMessageBox>
|
||||
#include <QClipboard>
|
||||
#include <QApplication>
|
||||
#include <QCheckBox>
|
||||
#include <QToolTip>
|
||||
*/
|
||||
|
||||
#include <mongo/client/mongo_uri.h>
|
||||
|
||||
#include "robomongo/core/settings/ConnectionSettings.h"
|
||||
#include "robomongo/core/utils/QtUtils.h"
|
||||
/* --- Disabling unfinished export URI connection string feature
|
||||
#include "robomongo/core/settings/CredentialSettings.h"
|
||||
#include "robomongo/core/settings/ReplicaSetSettings.h"
|
||||
#include "robomongo/core/settings/SslSettings.h"
|
||||
#include "robomongo/gui/utils/GuiConstants.h"
|
||||
*/
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
@@ -32,123 +16,23 @@ namespace Robomongo
|
||||
QLabel *defaultDatabaseDescriptionLabel = new QLabel(
|
||||
"Database, that will be default (<code>db</code> shell variable will point to this database). "
|
||||
"By default, default database will be the one you authenticate on, or <code>test</code> otherwise. "
|
||||
"Leave this field empty, if you want default behavior.");
|
||||
"Leave this field empty, if you want default behaviour.");
|
||||
defaultDatabaseDescriptionLabel->setWordWrap(true);
|
||||
defaultDatabaseDescriptionLabel->setContentsMargins(0, -2, 0, 20);
|
||||
|
||||
_defaultDatabaseName = new QLineEdit(QtUtils::toQString(_settings->defaultDatabase()));
|
||||
|
||||
/* --- Disabling unfinished export URI connection string feature
|
||||
_uriString = new QLineEdit;
|
||||
_uriString->setReadOnly(true);
|
||||
QGridLayout *connectionLayout = new QGridLayout;
|
||||
connectionLayout->setAlignment(Qt::AlignTop);
|
||||
connectionLayout->addWidget(new QLabel("Default Database:"), 1, 0);
|
||||
connectionLayout->addWidget(_defaultDatabaseName, 1, 1, 1, 1);
|
||||
connectionLayout->addWidget(defaultDatabaseDescriptionLabel, 2, 1, 1, 1);
|
||||
|
||||
_includePasswordCheckBox = new QCheckBox("Include passwords");
|
||||
VERIFY(connect(_includePasswordCheckBox, SIGNAL(toggled(bool)),
|
||||
this, SLOT(on_includePasswordsCheckBox_toggle(bool))));
|
||||
|
||||
auto generateButton = new QPushButton("Generate");
|
||||
generateButton->setFixedWidth(70);
|
||||
generateButton->setMaximumHeight(HighDpiConstants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
VERIFY(connect(generateButton, SIGNAL(clicked()), this, SLOT(on_generateButton_clicked())));
|
||||
|
||||
_copyButton = new QPushButton("Copy");
|
||||
_copyButton->setFixedWidth(50);
|
||||
_copyButton->setMaximumHeight(HighDpiConstants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
VERIFY(connect(_copyButton, SIGNAL(clicked()), this, SLOT(on_copyButton_clicked())));
|
||||
|
||||
auto hlay = new QHBoxLayout;
|
||||
hlay->addWidget(_includePasswordCheckBox);
|
||||
hlay->addWidget(generateButton, Qt::AlignLeft);
|
||||
hlay->addWidget(_copyButton, Qt::AlignLeft);
|
||||
*/
|
||||
|
||||
auto mainLayout = new QGridLayout;
|
||||
mainLayout->setAlignment(Qt::AlignTop);
|
||||
mainLayout->addWidget(new QLabel("Default Database:"), 1, 0);
|
||||
mainLayout->addWidget(_defaultDatabaseName, 1, 1, 1, 2);
|
||||
mainLayout->addWidget(defaultDatabaseDescriptionLabel, 2, 1, 1, 2);
|
||||
/* --- Disabling unfinished export URI connection string feature
|
||||
mainLayout->addWidget(new QLabel{ "URI Connection String:" }, 3, 0);
|
||||
mainLayout->addWidget(_uriString, 3, 1);
|
||||
mainLayout->addLayout(hlay, 4, 1);
|
||||
*/
|
||||
setLayout(mainLayout);
|
||||
setLayout(connectionLayout);
|
||||
}
|
||||
|
||||
void ConnectionAdvancedTab::accept()
|
||||
{
|
||||
_settings->setDefaultDatabase(QtUtils::toStdString(_defaultDatabaseName->text()));
|
||||
}
|
||||
|
||||
/* --- Disabling unfinished export URI connection string feature
|
||||
void ConnectionAdvancedTab::on_generateButton_clicked()
|
||||
{
|
||||
if (_settings->isReplicaSet()) {
|
||||
// todo:
|
||||
// handle set name will be empty initially. It will be available(cached) after first
|
||||
// successful connection.
|
||||
std::string connStr = { "mongodb://" };
|
||||
|
||||
// todo: which credential to use if there are more than one?
|
||||
if (_settings->hasEnabledPrimaryCredential() && !_settings->credentials().isEmpty()) {
|
||||
connStr.append(_settings->primaryCredential()->userName() + ":");
|
||||
connStr.append(_includePasswordCheckBox->isChecked() ?
|
||||
_settings->primaryCredential()->userPassword() : "PASSWORD");
|
||||
connStr.append("@");
|
||||
}
|
||||
|
||||
for (auto const& member : _settings->replicaSetSettings()->membersToHostAndPort()) {
|
||||
connStr.append(member.toString() + ",");
|
||||
}
|
||||
connStr.pop_back(); // delete last ","
|
||||
|
||||
connStr.append("/admin?");
|
||||
|
||||
connStr.append("replicaSet=" + _settings->replicaSetSettings()->setName());
|
||||
|
||||
if (_settings->sslSettings()->sslEnabled())
|
||||
connStr.append("&ssl=true");
|
||||
|
||||
if (_settings->hasEnabledPrimaryCredential() && !_settings->credentials().isEmpty())
|
||||
connStr.append("&authSource=" + _settings->primaryCredential()->databaseName());
|
||||
|
||||
// todo: validate connStr
|
||||
_uriString->setText(QString::fromStdString(connStr));
|
||||
_uriString->setCursorPosition(QTextCursor::Start);
|
||||
|
||||
}
|
||||
else { // standalone server
|
||||
mongo::HostAndPort server = _settings->hostAndPort();
|
||||
mongo::ConnectionString connStr{ server };
|
||||
auto str1 = connStr.toString();
|
||||
|
||||
auto uriWithStatus = mongo::StatusWith<mongo::MongoURI>(mongo::MongoURI::parse(connStr.toString()));
|
||||
auto str2 = uriWithStatus.getValue().toString();
|
||||
|
||||
_uriString->setText(QString::fromStdString("mongodb://" + str1 + "/admin"));
|
||||
_uriString->setCursorPosition(QTextCursor::Start);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionAdvancedTab::on_copyButton_clicked()
|
||||
{
|
||||
if (_uriString->text().isEmpty())
|
||||
return;
|
||||
|
||||
QClipboard *clipboard = qApp->clipboard();
|
||||
clipboard->setText(_uriString->text());
|
||||
|
||||
auto posUnderGenerateButton = QPoint(_copyButton->pos().x()-100, _copyButton->y()+20);
|
||||
QToolTip::showText(mapToGlobal(posUnderGenerateButton), "Copied into clipboard", nullptr, QRect(), 2000);
|
||||
}
|
||||
|
||||
void ConnectionAdvancedTab::on_includePasswordsCheckBox_toggle(bool checked)
|
||||
{
|
||||
if (_uriString->text().isEmpty())
|
||||
return;
|
||||
|
||||
on_generateButton_clicked();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLineEdit;
|
||||
class QCheckBox;
|
||||
class QPushButton;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Robomongo
|
||||
@@ -18,24 +16,10 @@ namespace Robomongo
|
||||
|
||||
public:
|
||||
ConnectionAdvancedTab(ConnectionSettings *settings);
|
||||
QLineEdit *_defaultDatabaseName;
|
||||
void accept();
|
||||
|
||||
/* --- Disabling unfinished export URI connection string feature
|
||||
private Q_SLOTS :
|
||||
void on_generateButton_clicked();
|
||||
void on_copyButton_clicked();
|
||||
void on_includePasswordsCheckBox_toggle(bool checked);
|
||||
*/
|
||||
|
||||
private:
|
||||
QLineEdit *_defaultDatabaseName;
|
||||
|
||||
/* --- Disabling unfinished export URI connection string feature
|
||||
QLineEdit *_uriString;
|
||||
QCheckBox *_includePasswordCheckBox;
|
||||
QPushButton *_copyButton;
|
||||
*/
|
||||
|
||||
ConnectionSettings *_settings;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Robomongo
|
||||
#endif
|
||||
// Attempt to fix the issue for Windows High DPI button height is slightly taller than other widgets
|
||||
#ifdef Q_OS_WIN
|
||||
_echoModeButton->setMaximumHeight(HighDpiConstants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
_echoModeButton->setMaximumHeight(HighDpiContants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
#endif
|
||||
VERIFY(connect(_echoModeButton, SIGNAL(clicked()), this, SLOT(toggleEchoMode())));
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "robomongo/gui/dialogs/ConnectionBasicTab.h"
|
||||
#include "robomongo/gui/dialogs/ConnectionBasicTab.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
@@ -8,26 +8,26 @@
|
||||
#include <QPushButton>
|
||||
#include <QFileDialog>
|
||||
#include <QComboBox>
|
||||
#include <QTreeWidget>
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QMessageBox>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
#include <QListWidget>
|
||||
#include <QListWidgetItem>
|
||||
#include <QShortCut>
|
||||
#include <QKeySequence>
|
||||
|
||||
#include "robomongo/core/utils/QtUtils.h"
|
||||
#include "robomongo/core/settings/ConnectionSettings.h"
|
||||
#include "robomongo/core/settings/ReplicaSetSettings.h"
|
||||
#include "robomongo/gui/GuiRegistry.h"
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
ConnectionBasicTab::ConnectionBasicTab(ConnectionSettings *settings) :
|
||||
_settings(settings)
|
||||
{
|
||||
const ReplicaSetSettings* const replicaSettings = _settings->replicaSetSettings();
|
||||
|
||||
_typeLabel = new QLabel("Type:");
|
||||
_connectionType = new QComboBox;
|
||||
_connectionType->addItem(tr("Direct Connection"));
|
||||
_connectionType->addItem(tr("Replica Set"));
|
||||
_connectionType->addItem(tr("Replica Set or Sharded Cluster"));
|
||||
_connectionType->setCurrentIndex(static_cast<int>(_settings->isReplicaSet()));
|
||||
VERIFY(connect(_connectionType, SIGNAL(currentIndexChanged(int)), this, SLOT(on_ConnectionTypeChange(int))));
|
||||
|
||||
@@ -49,66 +49,56 @@ namespace Robomongo
|
||||
_addInfoLabel->setContentsMargins(0, -2, 0, 20);
|
||||
|
||||
_membersLabel = new QLabel("Members:");
|
||||
_membersLabel->setFixedWidth(_membersLabel->sizeHint().width());
|
||||
_members = new QTreeWidget;
|
||||
_members->setHeaderHidden(true);
|
||||
_members->setIndentation(0);
|
||||
#ifdef _WIN32
|
||||
auto lineHeight = _members->fontMetrics().height();
|
||||
_members->setFixedHeight(lineHeight * 8);
|
||||
#endif
|
||||
VERIFY(connect(_members, SIGNAL(itemChanged(QTreeWidgetItem*, int)),
|
||||
this, SLOT(on_replicaMemberItemEdit(QTreeWidgetItem*, int))));
|
||||
|
||||
if (_settings->isReplicaSet() && _settings->replicaSetSettings()->members().size() > 0) {
|
||||
for (const std::string& str : _settings->replicaSetSettings()->members()) {
|
||||
if (!str.empty()) {
|
||||
auto item = new QTreeWidgetItem;
|
||||
item->setText(0, QString::fromStdString(str));
|
||||
_members = new QListWidget;
|
||||
if (_settings->isReplicaSet())
|
||||
{
|
||||
if (replicaSettings->members().empty())
|
||||
{
|
||||
auto item = new QListWidgetItem("localhost:27017");
|
||||
item->setFlags(item->flags() | Qt::ItemIsEditable);
|
||||
_members->addItem(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const std::string& str : replicaSettings->members())
|
||||
{
|
||||
auto item = new QListWidgetItem(QString::fromStdString(str));
|
||||
item->setFlags(item->flags() | Qt::ItemIsEditable);
|
||||
_members->addTopLevelItem(item);
|
||||
_members->addItem(item);
|
||||
}
|
||||
}
|
||||
// To fix strange MAC alignment issue
|
||||
#ifndef _WIN32
|
||||
auto lineHeight = _members->fontMetrics().height();
|
||||
_members->setFixedHeight(lineHeight * 8);
|
||||
#endif
|
||||
}
|
||||
else { // No members
|
||||
auto item = new QTreeWidgetItem;
|
||||
item->setText(0, "localhost:27017");
|
||||
item->setFlags(item->flags() | Qt::ItemIsEditable);
|
||||
_members->addTopLevelItem(item);
|
||||
}
|
||||
|
||||
int const BUTTON_SIZE = 60;
|
||||
_addButton = new QPushButton;
|
||||
_addButton->setIcon(GuiRegistry::instance().plusIcon());
|
||||
_removeButton = new QPushButton;
|
||||
_removeButton->setIcon(GuiRegistry::instance().minusIcon());
|
||||
_addButton = new QPushButton("Add");
|
||||
_addButton->setFixedWidth(BUTTON_SIZE);
|
||||
_removeButton = new QPushButton("Remove");
|
||||
_removeButton->setFixedWidth(BUTTON_SIZE);
|
||||
_discoverButton = new QPushButton("Discover");
|
||||
_discoverButton->setFixedWidth(BUTTON_SIZE);
|
||||
VERIFY(connect(_addButton, SIGNAL(clicked()), this, SLOT(on_addButton_clicked())));
|
||||
VERIFY(connect(_removeButton, SIGNAL(clicked()), this, SLOT(on_removeButton_clicked())));
|
||||
|
||||
_minusPlusButtonBox = new QDialogButtonBox(this);
|
||||
_minusPlusButtonBox->setOrientation(Qt::Horizontal);
|
||||
#ifdef _WIN32
|
||||
_minusPlusButtonBox->addButton(_addButton, QDialogButtonBox::NoRole);
|
||||
_minusPlusButtonBox->addButton(_removeButton, QDialogButtonBox::NoRole);
|
||||
#else
|
||||
_minusPlusButtonBox->addButton(_removeButton, QDialogButtonBox::NoRole);
|
||||
_minusPlusButtonBox->addButton(_addButton, QDialogButtonBox::NoRole);
|
||||
#endif
|
||||
auto hLayout = new QHBoxLayout;
|
||||
hLayout->addWidget(_addButton);
|
||||
hLayout->addWidget(_removeButton);
|
||||
hLayout->addWidget(_discoverButton);
|
||||
hLayout->setAlignment(Qt::AlignRight);
|
||||
|
||||
_setNameLabel = new QLabel("Set Name:<br><i><font color=\"gray\">(Optional)</font></i>");
|
||||
_setNameEdit = new QLineEdit(QString::fromStdString(_settings->replicaSetSettings()->setNameUserEntered()));
|
||||
auto _optionalLabel = new QLabel("<i><font color=\"gray\">(Optional)</font></i>");
|
||||
_readPrefLabel = new QLabel("Read Preference:");
|
||||
_readPrefLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||
_readPreference = new QComboBox;
|
||||
_readPreference->addItems(QStringList({ "Primary", "Primary Preferred" })); //todo
|
||||
if (_settings->isReplicaSet()) {
|
||||
_readPreference->setCurrentIndex(static_cast<int>(replicaSettings->readPreference()));
|
||||
}
|
||||
|
||||
auto connectionLayout = new QGridLayout;
|
||||
connectionLayout->setVerticalSpacing(10);
|
||||
|
||||
new QShortcut(QKeySequence(Qt::Key_Delete), this, SLOT(deleteItem()));
|
||||
|
||||
QGridLayout *connectionLayout = new QGridLayout;
|
||||
connectionLayout->setAlignment(Qt::AlignTop);
|
||||
connectionLayout->addWidget(_typeLabel, 1, 0);
|
||||
connectionLayout->addWidget(_connectionType, 1, 1, 1, 3);
|
||||
connectionLayout->addWidget(_connectionType, 1, 1, 1, 3);
|
||||
connectionLayout->addWidget(new QLabel(""), 2, 0);
|
||||
connectionLayout->addWidget(_nameLabel, 3, 0);
|
||||
connectionLayout->addWidget(_connectionName, 3, 1, 1, 3);
|
||||
@@ -119,85 +109,42 @@ namespace Robomongo
|
||||
connectionLayout->addWidget(_serverPort, 5, 3);
|
||||
connectionLayout->addWidget(_addInfoLabel, 6, 1, 1, 3);
|
||||
connectionLayout->addWidget(_membersLabel, 7, 0, Qt::AlignTop);
|
||||
connectionLayout->addWidget(_members, 7, 1, 1, 3);
|
||||
connectionLayout->addWidget(_minusPlusButtonBox, 8, 3, Qt::AlignRight | Qt::AlignTop);
|
||||
connectionLayout->addWidget(_members, 7, 1, 1, 3);
|
||||
connectionLayout->addLayout(hLayout, 8, 1, 1, 3, Qt::AlignRight);
|
||||
connectionLayout->addWidget(new QLabel(""), 9, 0);
|
||||
connectionLayout->addWidget(_setNameLabel, 10, 0/*, Qt::AlignBottom*/);
|
||||
connectionLayout->addWidget(_setNameEdit, 10, 1, 1, 3, Qt::AlignTop);
|
||||
//connectionLayout->addWidget(_optionalLabel, 11, 1, 1, 3, Qt::AlignLeft | Qt::AlignTop);
|
||||
connectionLayout->addWidget(new QLabel(""), 12, 0);
|
||||
connectionLayout->addWidget(_readPrefLabel, 10, 0);
|
||||
connectionLayout->addWidget(_readPreference, 10, 1, 1, 3);
|
||||
connectionLayout->addWidget(new QLabel(""), 11, 0);
|
||||
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(connectionLayout);
|
||||
setLayout(mainLayout);
|
||||
|
||||
_connectionName->setFocus();
|
||||
on_ConnectionTypeChange(_connectionType->currentIndex());
|
||||
|
||||
}
|
||||
|
||||
bool ConnectionBasicTab::accept()
|
||||
void ConnectionBasicTab::accept()
|
||||
{
|
||||
ReplicaSetSettings* const replicaSettings = _settings->replicaSetSettings();
|
||||
|
||||
_settings->setReplicaSet(static_cast<bool>(_connectionType->currentIndex()));
|
||||
_settings->setConnectionName(QtUtils::toStdString(_connectionName->text()));
|
||||
|
||||
if (_settings->isReplicaSet() && _members->topLevelItemCount() == 0) {
|
||||
QMessageBox::critical(this, "Error", "Replica set members cannot be empty. "
|
||||
"Please enter at least one member.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check and warn if there is duplicate member or
|
||||
// if any of the replica set member items does not contain ":" character between hostname and port.
|
||||
if (_settings->isReplicaSet() && _members->topLevelItemCount() > 1) {
|
||||
QStringList members;
|
||||
for (int i = 0; i < _members->topLevelItemCount(); ++i) {
|
||||
QTreeWidgetItem const* item = _members->topLevelItem(i);
|
||||
QStringList const hostAndPort = item->text(0).split(":");
|
||||
if (hostAndPort.size() < 2) {
|
||||
QMessageBox::critical(this, "Error", "Replica set member items must all contain ':' between"
|
||||
" hostname and port.");
|
||||
return false;
|
||||
}
|
||||
if (!item->text(0).isEmpty())
|
||||
members.push_back(item->text(0));
|
||||
}
|
||||
if (members.size() > 1) {
|
||||
if (members.removeDuplicates() > 0) {
|
||||
QMessageBox::critical(this, "Error", "Please remove duplicate member, two replica"
|
||||
" set members cannot have the same hostname and port.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save to settings
|
||||
if (_settings->isReplicaSet() && _members->topLevelItemCount() > 0) {
|
||||
QStringList const hostAndPort = _members->topLevelItem(0)->text(0).split(":");
|
||||
_settings->setServerHost(hostAndPort[0].toStdString());
|
||||
_settings->setServerPort(hostAndPort[1].toInt());
|
||||
}
|
||||
else { // Single server
|
||||
_settings->setServerHost(QtUtils::toStdString(_serverAddress->text()));
|
||||
_settings->setServerPort(_serverPort->text().toInt());
|
||||
}
|
||||
|
||||
_settings->setServerHost(QtUtils::toStdString(_serverAddress->text()));
|
||||
_settings->setServerPort(_serverPort->text().toInt());
|
||||
if (_settings->isReplicaSet()) {
|
||||
// Save replica members
|
||||
// save replica members
|
||||
std::vector<std::string> members;
|
||||
for (int i = 0; i < _members->topLevelItemCount(); ++i)
|
||||
for (int i = 0; i < _members->count(); ++i)
|
||||
{
|
||||
QTreeWidgetItem const* item = _members->topLevelItem(i);
|
||||
if (!item->text(0).isEmpty())
|
||||
members.push_back(item->text(0).toStdString());
|
||||
QListWidgetItem const* item = _members->item(i);
|
||||
members.push_back(item->text().toStdString());
|
||||
}
|
||||
_settings->replicaSetSettings()->setMembers(members);
|
||||
_settings->replicaSetSettings()->setSetNameUserEntered(_setNameEdit->text().toStdString());
|
||||
// Clear cached set name
|
||||
_settings->replicaSetSettings()->setCachedSetName("");
|
||||
replicaSettings->setMembers(members);
|
||||
// save read preference option
|
||||
replicaSettings->setReadPreference(
|
||||
static_cast<ReplicaSetSettings::ReadPreference>(_readPreference->currentIndex()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConnectionBasicTab::on_ConnectionTypeChange(int index)
|
||||
@@ -207,10 +154,12 @@ namespace Robomongo
|
||||
// Replica set
|
||||
_membersLabel->setVisible(isReplica);
|
||||
_members->setVisible(isReplica);
|
||||
_minusPlusButtonBox->setVisible(isReplica);
|
||||
_setNameLabel->setVisible(isReplica);
|
||||
_setNameEdit->setVisible(isReplica);
|
||||
|
||||
_addButton->setVisible(isReplica);
|
||||
_removeButton->setVisible(isReplica);
|
||||
_discoverButton->setVisible(isReplica);
|
||||
_readPrefLabel->setVisible(isReplica);
|
||||
_readPreference->setVisible(isReplica);
|
||||
|
||||
// Direct Connection
|
||||
_addressLabel->setVisible(!isReplica);
|
||||
_serverAddress->setVisible(!isReplica);
|
||||
@@ -226,68 +175,8 @@ namespace Robomongo
|
||||
|
||||
void ConnectionBasicTab::on_addButton_clicked()
|
||||
{
|
||||
auto item = new QTreeWidgetItem;
|
||||
|
||||
// Make member addition little smarter than expected
|
||||
if (_members->topLevelItemCount() < 1) {
|
||||
item->setText(0, "localhost:27017");
|
||||
}
|
||||
else { // Add the next member using last entered hostname and incremented port by one
|
||||
QString const& lastMember = _members->topLevelItem(_members->topLevelItemCount()-1)->text(0);
|
||||
QStringList const& hostAndPort = lastMember.split(':');
|
||||
if (hostAndPort.size() == 2) {
|
||||
auto const& hostName = hostAndPort[0];
|
||||
auto const& port = hostAndPort[1].toInt();
|
||||
item->setText(0, hostName + ':' + QString::number(port + 1));
|
||||
}
|
||||
else {
|
||||
item->setText(0, "localhost:" + QString::number(_members->topLevelItemCount() + 27017));
|
||||
}
|
||||
}
|
||||
|
||||
auto item = new QListWidgetItem("localhost:27017");
|
||||
item->setFlags(item->flags() | Qt::ItemIsEditable);
|
||||
_members->addTopLevelItem(item);
|
||||
}
|
||||
|
||||
void ConnectionBasicTab::on_removeButton_clicked()
|
||||
{
|
||||
if (_members->topLevelItemCount() <= 0)
|
||||
return;
|
||||
|
||||
if (_members->currentItem())
|
||||
delete _members->currentItem();
|
||||
else
|
||||
delete _members->topLevelItem(_members->topLevelItemCount() - 1);
|
||||
}
|
||||
|
||||
void ConnectionBasicTab::on_replicaMemberItemEdit(QTreeWidgetItem* item, int column)
|
||||
{
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
auto str = item->text(0);
|
||||
|
||||
// Remove white spaces
|
||||
str = str.simplified();
|
||||
str.remove(" ");
|
||||
|
||||
// Remove item from tree widget if it has empty text
|
||||
if (str.isEmpty()) {
|
||||
delete item;
|
||||
return;
|
||||
}
|
||||
|
||||
// Force port as integer
|
||||
QStringList const& hostAndPort = str.split(':');
|
||||
if (hostAndPort.size() >= 2) {
|
||||
auto const& hostName = hostAndPort[0];
|
||||
auto portStr = hostAndPort[1];
|
||||
portStr.remove(QRegExp("[^\\d]"));
|
||||
str = hostName + ':' + QString::number(portStr.toInt());
|
||||
}
|
||||
else
|
||||
str += ":27017";
|
||||
|
||||
item->setText(0, str);
|
||||
_members->addItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@ class QLabel;
|
||||
class QCheckBox;
|
||||
class QPushButton;
|
||||
class QComboBox;
|
||||
class QTreeWidget;
|
||||
class QTreeWidgetItem;
|
||||
class QDialogButtonBox;
|
||||
class QListWidget;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Robomongo
|
||||
@@ -22,14 +20,12 @@ namespace Robomongo
|
||||
|
||||
public:
|
||||
ConnectionBasicTab(ConnectionSettings *settings);
|
||||
bool accept();
|
||||
void accept();
|
||||
|
||||
private Q_SLOTS:
|
||||
void on_ConnectionTypeChange(int index);
|
||||
void deleteItem();
|
||||
void on_addButton_clicked();
|
||||
void on_removeButton_clicked();
|
||||
void on_replicaMemberItemEdit(QTreeWidgetItem* item, int column);
|
||||
|
||||
private:
|
||||
QLabel *_typeLabel;
|
||||
@@ -43,16 +39,12 @@ namespace Robomongo
|
||||
QLineEdit *_serverPort;
|
||||
QLabel *_addInfoLabel;
|
||||
QLabel *_membersLabel;
|
||||
QTreeWidget *_members;
|
||||
QListWidget *_members;
|
||||
QPushButton *_addButton;
|
||||
QPushButton *_removeButton;
|
||||
QDialogButtonBox *_minusPlusButtonBox;
|
||||
QLabel *_setNameLabel;
|
||||
QLineEdit *_setNameEdit;
|
||||
QPushButton *_discoverButton;
|
||||
QLabel *_readPrefLabel;
|
||||
QComboBox *_readPreference;
|
||||
|
||||
ConnectionSettings *const _settings;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "robomongo/core/settings/CredentialSettings.h"
|
||||
#include "robomongo/core/settings/SshSettings.h"
|
||||
#include "robomongo/core/settings/SslSettings.h"
|
||||
#include "robomongo/core/settings/ReplicaSetSettings.h"
|
||||
#include "robomongo/gui/GuiRegistry.h"
|
||||
#include "robomongo/core/AppRegistry.h"
|
||||
#include "robomongo/core/domain/App.h"
|
||||
@@ -24,11 +23,13 @@ namespace Robomongo
|
||||
{
|
||||
ConnectionDiagnosticDialog::ConnectionDiagnosticDialog(ConnectionSettings *connection, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
_connSettings(connection->clone()),
|
||||
_connection(NULL),
|
||||
_server(NULL),
|
||||
_serverHandle(0),
|
||||
_continueExec(true)
|
||||
{
|
||||
_connection = connection->clone();
|
||||
|
||||
AppRegistry::instance().bus()->subscribe(this, ConnectionEstablishedEvent::Type);
|
||||
AppRegistry::instance().bus()->subscribe(this, ConnectionFailedEvent::Type);
|
||||
|
||||
@@ -96,7 +97,7 @@ namespace Robomongo
|
||||
|
||||
_viewErrorLink->hide();
|
||||
|
||||
if (!AppRegistry::instance().app()->openServer(_connSettings, ConnectionTest)) {
|
||||
if (!AppRegistry::instance().app()->openServer(_connection, ConnectionTest)) {
|
||||
_continueExec = false;
|
||||
return;
|
||||
}
|
||||
@@ -118,7 +119,7 @@ namespace Robomongo
|
||||
|
||||
void ConnectionDiagnosticDialog::sshStatus(State state)
|
||||
{
|
||||
if (!_connSettings->sshSettings()->enabled()) {
|
||||
if (!_connection->sshSettings()->enabled()) {
|
||||
_sshIconLabel->setVisible(false);
|
||||
_sshLabel->setVisible(false);
|
||||
return;
|
||||
@@ -127,18 +128,18 @@ namespace Robomongo
|
||||
if (state == InitialState) {
|
||||
_sshIconLabel->setMovie(_loadingMovie);
|
||||
_sshLabel->setText(QString("Connecting to SSH server at <b>%1:%2</b>...")
|
||||
.arg(QtUtils::toQString(_connSettings->sshSettings()->host()))
|
||||
.arg(_connSettings->sshSettings()->port()));
|
||||
.arg(QtUtils::toQString(_connection->sshSettings()->host()))
|
||||
.arg(_connection->sshSettings()->port()));
|
||||
} else if (state == CompletedState) {
|
||||
_sshIconLabel->setPixmap(_yesPixmap);
|
||||
_sshLabel->setText(QString("Connected to SSH server at <b>%1:%2</b>")
|
||||
.arg(QtUtils::toQString(_connSettings->sshSettings()->host()))
|
||||
.arg(_connSettings->sshSettings()->port()));
|
||||
.arg(QtUtils::toQString(_connection->sshSettings()->host()))
|
||||
.arg(_connection->sshSettings()->port()));
|
||||
} else if (state == FailedState) {
|
||||
_sshIconLabel->setPixmap(_noPixmap);
|
||||
_sshLabel->setText(QString("Unable to connect to SSH server at <b>%1:%2</b>")
|
||||
.arg(QtUtils::toQString(_connSettings->sshSettings()->host()))
|
||||
.arg(_connSettings->sshSettings()->port()));
|
||||
.arg(QtUtils::toQString(_connection->sshSettings()->host()))
|
||||
.arg(_connection->sshSettings()->port()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,45 +147,34 @@ namespace Robomongo
|
||||
{
|
||||
// Add info about tunneling if SSH or SSL is used
|
||||
QString tunnelNote(""); // No tunnel info when neither SSH nor SSL enabled
|
||||
if (_connSettings->sshSettings()->enabled())
|
||||
if (_connection->sshSettings()->enabled())
|
||||
{
|
||||
tunnelNote = " via SSH tunnel";
|
||||
else if (_connSettings->sslSettings()->sslEnabled())
|
||||
}
|
||||
else if (_connection->sslSettings()->sslEnabled())
|
||||
{
|
||||
tunnelNote = " via SSL tunnel";
|
||||
else
|
||||
tunnelNote = "";
|
||||
|
||||
|
||||
auto replicaSetStr = QString::fromStdString(_connSettings->connectionName()) + " [Replica Set]";
|
||||
replicaSetStr = (_connSettings->replicaSetSettings()->members().size() > 0)
|
||||
? replicaSetStr + '(' + QString::fromStdString(
|
||||
_connSettings->replicaSetSettings()->members()[0]) + ')'
|
||||
: replicaSetStr + "";
|
||||
|
||||
QString const& serverAddress = _connSettings->isReplicaSet()
|
||||
? replicaSetStr
|
||||
: QString::fromStdString(_connSettings->getFullAddress());
|
||||
}
|
||||
|
||||
// Set main info text at dialog
|
||||
if (state == InitialState) {
|
||||
_connectionIconLabel->setMovie(_loadingMovie);
|
||||
_connectionLabel->setText(QString("Connecting to <b>%1</b>%2...").arg(serverAddress, tunnelNote));
|
||||
|
||||
_connectionLabel->setText(QString("Connecting to <b>%1</b>%2...").arg(QtUtils::toQString(_connection->getFullAddress()), tunnelNote));
|
||||
} else if (state == CompletedState) {
|
||||
_connectionIconLabel->setPixmap(_yesPixmap);
|
||||
_connectionLabel->setText(QString("Connected to <b>%1</b>%2").arg(serverAddress, tunnelNote));
|
||||
_connectionLabel->setText(QString("Connected to <b>%1</b>%2").arg(QtUtils::toQString(_connection->getFullAddress()), tunnelNote));
|
||||
} else if (state == FailedState) {
|
||||
_connectionIconLabel->setPixmap(_noPixmap);
|
||||
_connectionLabel->setText(QString("Failed to connect to <b>%1</b>%2").arg(serverAddress, tunnelNote));
|
||||
_connectionLabel->setText(QString("Failed to connect to <b>%1</b>%2").arg(QtUtils::toQString(_connection->getFullAddress()), tunnelNote));
|
||||
} else if (state == NotPerformedState) {
|
||||
_connectionIconLabel->setPixmap(_questionPixmap);
|
||||
_connectionLabel->setText(QString("No chance to try connection to <b>%1</b>%2").
|
||||
arg(serverAddress, tunnelNote));
|
||||
_connectionLabel->setText(QString("No chance to try connection to <b>%1</b>%2").arg(QtUtils::toQString(_connection->getFullAddress()), tunnelNote));
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionDiagnosticDialog::authStatus(State state)
|
||||
{
|
||||
if (!_connSettings->hasEnabledPrimaryCredential()) {
|
||||
if (!_connection->hasEnabledPrimaryCredential()) {
|
||||
_authIconLabel->setVisible(false);
|
||||
_authLabel->setVisible(false);
|
||||
return;
|
||||
@@ -193,18 +183,18 @@ namespace Robomongo
|
||||
if (state == InitialState) {
|
||||
_authIconLabel->setMovie(_loadingMovie);
|
||||
_authLabel->setText(QString("Authorizing on <b>%1</b> database as <b>%2</b>...")
|
||||
.arg(QtUtils::toQString(_connSettings->primaryCredential()->databaseName()))
|
||||
.arg(QtUtils::toQString(_connSettings->primaryCredential()->userName())));
|
||||
.arg(QtUtils::toQString(_connection->primaryCredential()->databaseName()))
|
||||
.arg(QtUtils::toQString(_connection->primaryCredential()->userName())));
|
||||
} else if (state == CompletedState) {
|
||||
_authIconLabel->setPixmap(_yesPixmap);
|
||||
_authLabel->setText(QString("Authorized on <b>%1</b> database as <b>%2</b>")
|
||||
.arg(QtUtils::toQString(_connSettings->primaryCredential()->databaseName()))
|
||||
.arg(QtUtils::toQString(_connSettings->primaryCredential()->userName())));
|
||||
.arg(QtUtils::toQString(_connection->primaryCredential()->databaseName()))
|
||||
.arg(QtUtils::toQString(_connection->primaryCredential()->userName())));
|
||||
} else if (state == FailedState) {
|
||||
_authIconLabel->setPixmap(_noPixmap);
|
||||
_authLabel->setText(QString("Authorization failed on <b>%1</b> database as <b>%2</b>")
|
||||
.arg(QtUtils::toQString(_connSettings->primaryCredential()->databaseName()))
|
||||
.arg(QtUtils::toQString(_connSettings->primaryCredential()->userName())));
|
||||
.arg(QtUtils::toQString(_connection->primaryCredential()->databaseName()))
|
||||
.arg(QtUtils::toQString(_connection->primaryCredential()->userName())));
|
||||
} else if (state == NotPerformedState) {
|
||||
_authIconLabel->setPixmap(_questionPixmap);
|
||||
_authLabel->setText(QString("No chance to authorize"));
|
||||
@@ -213,7 +203,7 @@ namespace Robomongo
|
||||
|
||||
void ConnectionDiagnosticDialog::listStatus(State state)
|
||||
{
|
||||
if (_connSettings->hasEnabledPrimaryCredential()) {
|
||||
if (_connection->hasEnabledPrimaryCredential()) {
|
||||
_listIconLabel->setVisible(false);
|
||||
_listLabel->setVisible(false);
|
||||
return;
|
||||
|
||||
@@ -8,7 +8,7 @@ class QMovie;
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
struct ConnectionEstablishedEvent;
|
||||
class ConnectionEstablishedEvent;
|
||||
class ConnectionFailedEvent;
|
||||
class ConnectionSettings;
|
||||
class MongoServer;
|
||||
@@ -29,8 +29,7 @@ namespace Robomongo
|
||||
|
||||
private:
|
||||
|
||||
enum State
|
||||
{
|
||||
enum State {
|
||||
InitialState,
|
||||
CompletedState,
|
||||
FailedState,
|
||||
@@ -42,7 +41,7 @@ namespace Robomongo
|
||||
void authStatus(State state);
|
||||
void listStatus(State state);
|
||||
|
||||
ConnectionSettings *_connSettings;
|
||||
ConnectionSettings *_connection;
|
||||
QIcon _yesIcon;
|
||||
QIcon _noIcon;
|
||||
QIcon _questionIcon;
|
||||
|
||||
@@ -91,11 +91,11 @@ namespace Robomongo
|
||||
"Please use one of them.");
|
||||
return false;
|
||||
}
|
||||
|
||||
_basicTab->accept();
|
||||
_authTab->accept();
|
||||
_advancedTab->accept();
|
||||
|
||||
if (!_basicTab->accept() || !_sshTab->accept() || !_sslTab->accept())
|
||||
if (!_sshTab->accept() || !_sslTab->accept())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -11,22 +11,15 @@
|
||||
#include <QKeyEvent>
|
||||
#include <QApplication>
|
||||
#include <QSettings>
|
||||
#include <QUuid>
|
||||
|
||||
#include "robomongo/core/AppRegistry.h"
|
||||
#include "robomongo/core/settings/ConnectionSettings.h"
|
||||
#include "robomongo/core/settings/ReplicaSetSettings.h"
|
||||
#include "robomongo/core/settings/SettingsManager.h"
|
||||
#include "robomongo/core/settings/SslSettings.h"
|
||||
#include "robomongo/core/settings/SshSettings.h"
|
||||
#include "robomongo/core/settings/CredentialSettings.h"
|
||||
#include "robomongo/core/settings/SettingsManager.h"
|
||||
#include "robomongo/core/utils/QtUtils.h"
|
||||
|
||||
#include "robomongo/gui/GuiRegistry.h"
|
||||
#include "robomongo/gui/dialogs/ConnectionDialog.h"
|
||||
#include "robomongo/gui/MainWindow.h"
|
||||
#include "robomongo/gui/widgets/workarea/WelcomeTab.h"
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
@@ -52,49 +45,36 @@ namespace Robomongo
|
||||
*/
|
||||
void setConnection(ConnectionSettings *connection)
|
||||
{
|
||||
_connection = connection;
|
||||
if (connection->isReplicaSet()) {
|
||||
setText(0, QtUtils::toQString(connection->connectionName()) + " [Replica Set]");
|
||||
auto const repSetSize = connection->replicaSetSettings()->members().size();
|
||||
setText(1, QString::number(repSetSize) + " Servers (" + QtUtils::toQString(connection->getFullAddress()) + ")");
|
||||
}
|
||||
else {
|
||||
setText(0, QtUtils::toQString(connection->connectionName()));
|
||||
setText(1, QtUtils::toQString(connection->getFullAddress()));
|
||||
}
|
||||
|
||||
if (_connection->isReplicaSet()) {
|
||||
if (connection->hasEnabledPrimaryCredential()) {
|
||||
QString authString = QString("%1 / %2").arg(QtUtils::toQString(connection->primaryCredential()->databaseName())).arg(QtUtils::toQString(connection->primaryCredential()->userName()));
|
||||
setText(2, authString);
|
||||
setIcon(2, GuiRegistry::instance().keyIcon());
|
||||
} else {
|
||||
setIcon(2, QIcon());
|
||||
setText(2, "");
|
||||
}
|
||||
|
||||
_connection = connection;
|
||||
if (connection->isReplicaSet()) {
|
||||
setIcon(0, GuiRegistry::instance().replicaSetIcon());
|
||||
setText(0, QtUtils::toQString(_connection->connectionName()));
|
||||
auto const repSetSize = _connection->replicaSetSettings()->members().size();
|
||||
auto addrText = QString::number(repSetSize) + ((repSetSize > 1) ? " nodes" : " node");
|
||||
if (!_connection->replicaSetSettings()->members().empty()) {
|
||||
addrText += QString::fromStdString(" (" + _connection->replicaSetSettings()->members().front() + ")");
|
||||
}
|
||||
setText(1, addrText);
|
||||
}
|
||||
else {
|
||||
setIcon(0, GuiRegistry::instance().serverIcon());
|
||||
setText(0, QtUtils::toQString(_connection->connectionName()));
|
||||
setText(1, QtUtils::toQString(_connection->getFullAddress()));
|
||||
}
|
||||
|
||||
if (_connection->imported()) {
|
||||
if (connection->imported()) {
|
||||
setIcon(0, GuiRegistry::instance().serverImportedIcon());
|
||||
}
|
||||
|
||||
// Header "Attributes" (column[2])
|
||||
setText(2, _connection->isReplicaSet() ? "Replica Set" : "");
|
||||
|
||||
if (_connection->sslSettings()->sslEnabled())
|
||||
setText(2, text(2) + (text(2).isEmpty() ? "SSL" : ", SSL"));
|
||||
|
||||
if (_connection->sshSettings()->enabled())
|
||||
setText(2, text(2) + (text(2).isEmpty() ? "SSH" : ", SSH"));
|
||||
|
||||
// Header "Auth. Database/User" (column[3])
|
||||
if (_connection->hasEnabledPrimaryCredential()) {
|
||||
auto authString = QString("%1 / %2").arg(QtUtils::toQString(_connection->primaryCredential()->databaseName()))
|
||||
.arg(QtUtils::toQString(_connection->primaryCredential()->userName()));
|
||||
setText(3, authString + " ");
|
||||
setIcon(3, GuiRegistry::instance().keyIcon());
|
||||
}
|
||||
else {
|
||||
setIcon(3, QIcon());
|
||||
setText(3, "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -133,13 +113,12 @@ namespace Robomongo
|
||||
_listWidget->setIndentation(5);
|
||||
|
||||
QStringList colums;
|
||||
colums << "Name" << "Address" << "Attributes" << "Auth. Database / User";
|
||||
colums << "Name" << "Address" << "Auth. Database / User";
|
||||
_listWidget->setHeaderLabels(colums);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
|
||||
_listWidget->header()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||
_listWidget->header()->setSectionResizeMode(1, QHeaderView::Stretch);
|
||||
_listWidget->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
|
||||
_listWidget->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
|
||||
_listWidget->header()->setSectionResizeMode(2, QHeaderView::Stretch);
|
||||
#endif
|
||||
//_listWidget->setViewMode(QListView::ListMode);
|
||||
_listWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
|
||||
@@ -204,19 +183,19 @@ namespace Robomongo
|
||||
mainLayout->addLayout(firstColumnLayout, 1);
|
||||
|
||||
// Populate list with connections
|
||||
std::vector<ConnectionSettings*> connectionSettings = _settingsManager->connections();
|
||||
for (auto const& connSetting : connectionSettings) {
|
||||
ConnectionSettings *connectionModel { connSetting };
|
||||
SettingsManager::ConnectionSettingsContainerType connections = _settingsManager->connections();
|
||||
for (SettingsManager::ConnectionSettingsContainerType::const_iterator it = connections.begin(); it != connections.end(); ++it) {
|
||||
ConnectionSettings *connectionModel = *it;
|
||||
add(connectionModel);
|
||||
}
|
||||
|
||||
// Highlight last item
|
||||
// Highlight first item
|
||||
if (_listWidget->topLevelItemCount() > 0)
|
||||
_listWidget->setCurrentItem(_listWidget->topLevelItem(_listWidget->topLevelItemCount()-1));
|
||||
_listWidget->setCurrentItem(_listWidget->topLevelItem(0));
|
||||
|
||||
_listWidget->setFocus();
|
||||
|
||||
restoreWindowSettings();
|
||||
restoreWindowsSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,27 +203,27 @@ namespace Robomongo
|
||||
*/
|
||||
void ConnectionsDialog::accept()
|
||||
{
|
||||
auto currentItem = dynamic_cast<ConnectionListWidgetItem*>(_listWidget->currentItem());
|
||||
ConnectionListWidgetItem *currentItem = (ConnectionListWidgetItem *) _listWidget->currentItem();
|
||||
|
||||
// Do nothing if no item selected
|
||||
if (!currentItem)
|
||||
return;
|
||||
|
||||
_selectedConnection = currentItem->connection();
|
||||
saveWindowSettings();
|
||||
saveWindowsSettings();
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void ConnectionsDialog::reject()
|
||||
{
|
||||
saveWindowSettings();
|
||||
saveWindowsSettings();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
void ConnectionsDialog::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
saveWindowSettings();
|
||||
saveWindowsSettings();
|
||||
QWidget::closeEvent(event);
|
||||
}
|
||||
|
||||
@@ -264,19 +243,19 @@ namespace Robomongo
|
||||
* @brief Initiate 'add' action, usually when user clicked on Add button
|
||||
*/
|
||||
void ConnectionsDialog::add()
|
||||
{
|
||||
auto newConnSettings = std::unique_ptr<ConnectionSettings>(new ConnectionSettings(false));
|
||||
ConnectionDialog editDialog(newConnSettings.get());
|
||||
{
|
||||
ConnectionSettings *newModel = new ConnectionSettings();
|
||||
ConnectionDialog editDialog(newModel);
|
||||
|
||||
// Do nothing if not accepted
|
||||
if (editDialog.exec() != QDialog::Accepted) {
|
||||
delete newModel;
|
||||
return;
|
||||
}
|
||||
|
||||
add(newConnSettings.get());
|
||||
_settingsManager->addConnection(newConnSettings.release());
|
||||
|
||||
_settingsManager->addConnection(newModel);
|
||||
_listWidget->setFocus();
|
||||
add(newModel);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,13 +263,14 @@ namespace Robomongo
|
||||
*/
|
||||
void ConnectionsDialog::edit()
|
||||
{
|
||||
auto currentItem = dynamic_cast<ConnectionListWidgetItem*>(_listWidget->currentItem());
|
||||
ConnectionListWidgetItem *currentItem =
|
||||
(ConnectionListWidgetItem *) _listWidget->currentItem();
|
||||
|
||||
// Do nothing if no item selected
|
||||
if (!currentItem)
|
||||
if (currentItem == 0)
|
||||
return;
|
||||
|
||||
auto connection = currentItem->connection();
|
||||
ConnectionSettings *connection = currentItem->connection();
|
||||
boost::scoped_ptr<ConnectionSettings> clonedConnection(connection->clone());
|
||||
ConnectionDialog editDialog(clonedConnection.get());
|
||||
|
||||
@@ -322,53 +302,42 @@ namespace Robomongo
|
||||
*/
|
||||
void ConnectionsDialog::remove()
|
||||
{
|
||||
auto currentItem = dynamic_cast<ConnectionListWidgetItem*>(_listWidget->currentItem());
|
||||
ConnectionListWidgetItem *currentItem =
|
||||
(ConnectionListWidgetItem *)_listWidget->currentItem();
|
||||
|
||||
// Do nothing if no item selected
|
||||
if (!currentItem)
|
||||
return;
|
||||
|
||||
ConnectionSettings *connSettings = currentItem->connection();
|
||||
ConnectionSettings *connectionModel = currentItem->connection();
|
||||
|
||||
// Ask user
|
||||
int const answer = QMessageBox::question(this,
|
||||
int answer = QMessageBox::question(this,
|
||||
"Connections",
|
||||
QString("Really delete \"%1\" connection?").arg(QtUtils::toQString(connSettings->getReadableName())),
|
||||
QString("Really delete \"%1\" connection?").arg(QtUtils::toQString(connectionModel->getReadableName())),
|
||||
QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton);
|
||||
|
||||
if (answer != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
/* Temporarily disabling Recent Connections feature
|
||||
_settingsManager->deleteRecentConnection(connSettings);
|
||||
// Remove from WelcomeTab
|
||||
for (auto widget : QApplication::topLevelWidgets()) {
|
||||
if (auto mainWin = dynamic_cast<MainWindow*>(widget))
|
||||
mainWin->getWelcomeTab()->removeRecentConnectionItem(connSettings);
|
||||
}
|
||||
*/
|
||||
|
||||
_settingsManager->removeConnection(connSettings);
|
||||
|
||||
_settingsManager->removeConnection(connectionModel);
|
||||
delete currentItem;
|
||||
}
|
||||
|
||||
void ConnectionsDialog::clone()
|
||||
{
|
||||
auto currentItem = dynamic_cast<ConnectionListWidgetItem*>(_listWidget->currentItem());
|
||||
ConnectionListWidgetItem *currentItem =
|
||||
(ConnectionListWidgetItem *) _listWidget->currentItem();
|
||||
|
||||
// Do nothing if no item selected
|
||||
if (!currentItem)
|
||||
if (currentItem == 0)
|
||||
return;
|
||||
|
||||
// Clone connection
|
||||
ConnectionSettings *connection = currentItem->connection()->clone();
|
||||
// This is a special clone which will actually be a new connection and must have unique UUID
|
||||
connection->setUuid(QUuid::createUuid().toString());
|
||||
std::string newConnectionName = "Copy of " + connection->connectionName();
|
||||
std::string newConnectionName = "Copy of "+connection->connectionName();
|
||||
|
||||
connection->setConnectionName(newConnectionName);
|
||||
connection->replicaSetSettings()->setCachedSetName("");
|
||||
|
||||
ConnectionDialog editDialog(connection);
|
||||
|
||||
@@ -388,13 +357,15 @@ namespace Robomongo
|
||||
*/
|
||||
void ConnectionsDialog::listWidget_layoutChanged()
|
||||
{
|
||||
int count = _listWidget->topLevelItemCount();
|
||||
|
||||
// Make childrens toplevel again. This is a bad, but quickiest item reordering
|
||||
// implementation.
|
||||
for (int i = 0; i < _listWidget->topLevelItemCount(); i++)
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
auto item = (ConnectionListWidgetItem *) _listWidget->topLevelItem(i);
|
||||
ConnectionListWidgetItem * item = (ConnectionListWidgetItem *) _listWidget->topLevelItem(i);
|
||||
if (item->childCount() > 0) {
|
||||
auto childItem = (ConnectionListWidgetItem *) item->child(0);
|
||||
ConnectionListWidgetItem *childItem = (ConnectionListWidgetItem *) item->child(0);
|
||||
item->removeChild(childItem);
|
||||
_listWidget->insertTopLevelItem(++i, childItem);
|
||||
_listWidget->setCurrentItem(childItem);
|
||||
@@ -402,10 +373,11 @@ namespace Robomongo
|
||||
}
|
||||
}
|
||||
|
||||
count = _listWidget->topLevelItemCount();
|
||||
SettingsManager::ConnectionSettingsContainerType items;
|
||||
for (int i = 0; i < _listWidget->topLevelItemCount(); i++)
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
auto item = (ConnectionListWidgetItem *) _listWidget->topLevelItem(i);
|
||||
ConnectionListWidgetItem * item = (ConnectionListWidgetItem *) _listWidget->topLevelItem(i);
|
||||
items.push_back(item->connection());
|
||||
}
|
||||
|
||||
@@ -417,9 +389,8 @@ namespace Robomongo
|
||||
*/
|
||||
void ConnectionsDialog::add(ConnectionSettings *connection)
|
||||
{
|
||||
auto item = new ConnectionListWidgetItem(connection);
|
||||
ConnectionListWidgetItem *item = new ConnectionListWidgetItem(connection);
|
||||
_listWidget->addTopLevelItem(item);
|
||||
_listWidget->setCurrentItem(item);
|
||||
_connectionItems.push_back(item);
|
||||
}
|
||||
|
||||
@@ -445,15 +416,15 @@ namespace Robomongo
|
||||
QDialog::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void ConnectionsDialog::restoreWindowSettings()
|
||||
void ConnectionsDialog::restoreWindowsSettings()
|
||||
{
|
||||
QSettings settings("3T", "Robomongo");
|
||||
QSettings settings("Paralect", "Robomongo");
|
||||
resize(settings.value("ConnectionsDialog/size").toSize());
|
||||
}
|
||||
|
||||
void ConnectionsDialog::saveWindowSettings() const
|
||||
void ConnectionsDialog::saveWindowsSettings() const
|
||||
{
|
||||
QSettings settings("3T", "Robomongo");
|
||||
QSettings settings("Paralect", "Robomongo");
|
||||
settings.setValue("ConnectionsDialog/size", size());
|
||||
}
|
||||
|
||||
|
||||
@@ -35,27 +35,27 @@ namespace Robomongo
|
||||
/**
|
||||
* @brief This function is called when user clicks on "Connect" button.
|
||||
*/
|
||||
void accept() override;
|
||||
virtual void accept();
|
||||
|
||||
/**
|
||||
* @brief Called when "Cancel" button clicked.
|
||||
*/
|
||||
void reject() override;
|
||||
virtual void reject();
|
||||
|
||||
/**
|
||||
* @brief Add connection to the list widget
|
||||
*/
|
||||
void add(ConnectionSettings *connection);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Reimplementing closeEvent in order to do some pre-close actions.
|
||||
*/
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
||||
private Q_SLOTS:
|
||||
void linkActivated(const QString &link);
|
||||
|
||||
/**
|
||||
* @brief Add connection to the list widget
|
||||
*/
|
||||
void add(ConnectionSettings *connection);
|
||||
|
||||
/**
|
||||
* @brief Initiate 'add' action, usually when user clicked on Add button
|
||||
*/
|
||||
@@ -84,19 +84,19 @@ namespace Robomongo
|
||||
*/
|
||||
void listWidget_layoutChanged();
|
||||
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief Restore window settings from system registry
|
||||
* @brief Restore windows settings from system registry
|
||||
*/
|
||||
void restoreWindowSettings();
|
||||
void restoreWindowsSettings();
|
||||
|
||||
/**
|
||||
* @brief Save windows settings into system registry
|
||||
*/
|
||||
void saveWindowSettings() const;
|
||||
void saveWindowsSettings() const;
|
||||
|
||||
/**
|
||||
* @brief ConnectionSettings, that was selected after pressing on
|
||||
|
||||
@@ -243,8 +243,7 @@ namespace Robomongo
|
||||
if (state) // resize, dialog is expanding
|
||||
{
|
||||
setMinimumSize(560, 440);
|
||||
_validateJsonButton->setHidden(_advancedOptions->currentIndex() == OPTIONS_TAB);
|
||||
QSettings settings("3T", "Robomongo");
|
||||
QSettings settings("Paralect", "Robomongo");
|
||||
if (settings.contains("CreateCollectionDialog/size"))
|
||||
{
|
||||
restoreWindowSettings();
|
||||
@@ -258,8 +257,7 @@ namespace Robomongo
|
||||
else // resize, dialog is shrinking
|
||||
{
|
||||
saveWindowSettings(); // save expanded geometry first
|
||||
_validateJsonButton->hide();
|
||||
setFixedSize(300, 150);
|
||||
setMinimumSize(300, 150);
|
||||
adjustSize();
|
||||
}
|
||||
}
|
||||
@@ -405,13 +403,13 @@ namespace Robomongo
|
||||
|
||||
void CreateCollectionDialog::saveWindowSettings() const
|
||||
{
|
||||
QSettings settings("3T", "Robomongo");
|
||||
QSettings settings("Paralect", "Robomongo");
|
||||
settings.setValue("CreateCollectionDialog/size", size());
|
||||
}
|
||||
|
||||
void CreateCollectionDialog::restoreWindowSettings()
|
||||
{
|
||||
QSettings settings("3T", "Robomongo");
|
||||
QSettings settings("Paralect", "Robomongo");
|
||||
resize(settings.value("CreateCollectionDialog/size").toSize());
|
||||
}
|
||||
|
||||
|
||||
@@ -84,18 +84,18 @@ namespace Robomongo
|
||||
/**
|
||||
* @brief Validate all input fields and make extraOptions object if all valid when create button clicked.
|
||||
*/
|
||||
void accept() override;
|
||||
virtual void accept();
|
||||
|
||||
/**
|
||||
* @brief Called when "Cancel" button clicked.
|
||||
*/
|
||||
void reject() override;
|
||||
virtual void reject();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Reimplementing closeEvent in order to do implement functionalities before close this dialog.
|
||||
* @brief Reimplementing closeEvent in order to do implement functioanlites before close this dialog.
|
||||
*/
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
||||
private Q_SLOTS:
|
||||
/**
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
#include "robomongo/gui/dialogs/CreateConnectionDialog.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QCloseEvent>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QMessageBox>
|
||||
#include <QApplication>
|
||||
#include <QSplitter>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QPixmap>
|
||||
#include <QLabel>
|
||||
|
||||
#include "robomongo/gui/GuiRegistry.h"
|
||||
#include "robomongo/gui/dialogs/ConnectionsDialog.h"
|
||||
#include "robomongo/gui/dialogs/ConnectionDiagnosticDialog.h"
|
||||
#include "robomongo/core/settings/ConnectionSettings.h"
|
||||
#include "robomongo/core/utils/QtUtils.h"
|
||||
|
||||
#include <mongo/client/connection_string.h>
|
||||
//#include <mongo/base/status_with.h>
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
/**
|
||||
* @brief Constructs dialog with specified connection
|
||||
*/
|
||||
CreateConnectionDialog::CreateConnectionDialog(ConnectionsDialog* parent)
|
||||
: QDialog(), _connectionsDialog(parent), _connection(nullptr), _fromURI(true), // todo: _fromURI:false
|
||||
_mongoUriWithStatus(nullptr)
|
||||
{
|
||||
setWindowTitle("Create New Connection");
|
||||
setWindowIcon(GuiRegistry::instance().serverIcon());
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); // Remove help button (?)
|
||||
setMinimumWidth(450);
|
||||
//setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
// Splitter-Left
|
||||
auto label01 = new QLabel("Replica Set");
|
||||
label01->setStyleSheet("font-weight: bold");
|
||||
auto wid1 = new QLabel;
|
||||
auto repSetImage = QPixmap("C:\\Users\\gsimsek\\Google Drive\\Cases - Drive\\replica_sets\\icons\\repset.png");
|
||||
wid1->setPixmap(repSetImage);
|
||||
|
||||
_uriLineEdit = new QLineEdit("mongodb://localhost:27017,localhost:27018,localhost:27019/admin?replicaSet=repset");
|
||||
|
||||
auto const& createConnStr= QString("b) <a style='color: %1' href='create'>Create connection manually</a>").arg("#106CD6");
|
||||
auto createConnLabel = new QLabel(createConnStr);
|
||||
VERIFY(connect(createConnLabel, SIGNAL(linkActivated(QString)), this, SLOT(on_createConnLinkActivated())));
|
||||
|
||||
auto splitterL = new QSplitter;
|
||||
splitterL->setOrientation(Qt::Vertical);
|
||||
splitterL->addWidget(label01);
|
||||
splitterL->addWidget(wid1);
|
||||
//splitterL->addWidget(new QLabel(""));
|
||||
//splitterL->addWidget(nameWid);
|
||||
splitterL->addWidget(new QLabel(""));
|
||||
splitterL->addWidget(new QLabel("a) I have a URI connection string:"));
|
||||
splitterL->addWidget(_uriLineEdit);
|
||||
splitterL->addWidget(new QLabel(""));
|
||||
splitterL->addWidget(createConnLabel);
|
||||
splitterL->addWidget(new QLabel(""));
|
||||
|
||||
|
||||
// Splitter-Right
|
||||
auto label2 = new QLabel("Stand Alone Server");
|
||||
label2->setStyleSheet("font-weight: bold");
|
||||
auto wid2 = new QLabel;
|
||||
auto standAlone = QPixmap("C:\\Users\\gsimsek\\Google Drive\\Cases - Drive\\replica_sets\\icons\\stand_alone.png");
|
||||
wid2->setPixmap(standAlone);
|
||||
|
||||
auto splitterR = new QSplitter;
|
||||
splitterR->setOrientation(Qt::Vertical);
|
||||
splitterR->addWidget(label2);
|
||||
splitterR->addWidget(wid2);
|
||||
|
||||
// Splitter layout
|
||||
auto splitterLay = new QHBoxLayout;
|
||||
splitterLay->addWidget(splitterL);
|
||||
//splitterLay->addWidget(splitterR);
|
||||
|
||||
// Button Box
|
||||
QPushButton *testButton = new QPushButton("&Test");
|
||||
testButton->setIcon(qApp->style()->standardIcon(QStyle::SP_MessageBoxInformation));
|
||||
VERIFY(connect(testButton, SIGNAL(clicked()), this, SLOT(testConnection())));
|
||||
|
||||
QHBoxLayout *bottomLayout = new QHBoxLayout;
|
||||
bottomLayout->addWidget(testButton, 1, Qt::AlignLeft);
|
||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
|
||||
buttonBox->setOrientation(Qt::Horizontal);
|
||||
buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Save);
|
||||
buttonBox->button(QDialogButtonBox::Save)->setText("Next");
|
||||
VERIFY(connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())));
|
||||
VERIFY(connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())));
|
||||
bottomLayout->addWidget(buttonBox);
|
||||
|
||||
// main layout
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(splitterLay);
|
||||
mainLayout->addLayout(bottomLayout);
|
||||
setLayout(mainLayout);
|
||||
|
||||
//_basicTab->setFocus();
|
||||
adjustSize();
|
||||
|
||||
// Set minimum width - adjustment after adding SSLTab
|
||||
setMinimumWidth(550);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accept() is called when user agree with entered data.
|
||||
*/
|
||||
void CreateConnectionDialog::accept()
|
||||
{
|
||||
//if (validateAndApply()) {
|
||||
// QDialog::accept();
|
||||
//}
|
||||
|
||||
std::unique_ptr<mongo::StatusWith<mongo::MongoURI>> uriWithStatus = getUriWithStatus();
|
||||
if (!uriWithStatus || !uriWithStatus->isOK()) {
|
||||
return;
|
||||
}
|
||||
_mongoUriWithStatus.reset(uriWithStatus.release());
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
bool CreateConnectionDialog::validateAndApply()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<mongo::StatusWith<mongo::MongoURI>> CreateConnectionDialog::getUriWithStatus()
|
||||
{
|
||||
const std::string& url = _uriLineEdit->text().toStdString();
|
||||
|
||||
std::unique_ptr<mongo::StatusWith<mongo::MongoURI>> uriWithStatus = nullptr;
|
||||
try {
|
||||
uriWithStatus.reset(new mongo::StatusWith<mongo::MongoURI>(mongo::MongoURI::parse(url)));
|
||||
if (!uriWithStatus->isOK()) {
|
||||
QMessageBox::critical(this, "Error", "Failed to parse connection string URI.\n"
|
||||
"Reason: " + QString::fromStdString(uriWithStatus->getStatus().reason()));
|
||||
return uriWithStatus;
|
||||
}
|
||||
}
|
||||
catch (const std::exception& exception) {
|
||||
QMessageBox::critical(this, "Error", "Failed to parse connection string URI.\n"
|
||||
"Reason: " + QString::fromStdString(exception.what()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return uriWithStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test current connection
|
||||
*/
|
||||
void CreateConnectionDialog::testConnection()
|
||||
{
|
||||
//if (!validateAndApply())
|
||||
// return;
|
||||
|
||||
auto uriWithStatus = getUriWithStatus();
|
||||
if (!uriWithStatus || !uriWithStatus->isOK()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto uri = uriWithStatus->getValue();
|
||||
ConnectionSettings connection(uri, true); // todo: refactor
|
||||
ConnectionDiagnosticDialog diag(&connection, this);
|
||||
if (!diag.continueExec())
|
||||
return;
|
||||
|
||||
diag.exec();
|
||||
}
|
||||
|
||||
void CreateConnectionDialog::on_createConnLinkActivated()
|
||||
{
|
||||
_fromURI = false;
|
||||
accept();
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLineEdit;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#include "robomongo/core/Core.h"
|
||||
|
||||
#include <mongo/client/mongo_uri.h>
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
class ConnectionsDialog;
|
||||
class ConnectionSettings;
|
||||
|
||||
/**
|
||||
* @brief This class is not finished, it is still under development.
|
||||
* It was planned to be used as very first dialog right after 'create' new
|
||||
* connection is clicked on connections dialog in order to provide user
|
||||
* some create more friendly create connection options with pictures
|
||||
* e.g. create connection from URI string, create replica set or create single server.
|
||||
*/
|
||||
class CreateConnectionDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using MongoURIwithStatus = mongo::StatusWith<mongo::MongoURI>;
|
||||
|
||||
/**
|
||||
* @brief Constructs dialog with specified connection
|
||||
*/
|
||||
CreateConnectionDialog(ConnectionsDialog *parent);
|
||||
ConnectionSettings *const connection() const { return _connection; }
|
||||
|
||||
// todo:
|
||||
// mongo::MongoURI getMongoUri() const { return _mongoUri; }
|
||||
bool fromURI() const { return _fromURI; }
|
||||
|
||||
std::unique_ptr<mongo::StatusWith<mongo::MongoURI>> getMongoUriWithStatus()
|
||||
{
|
||||
return std::move(_mongoUriWithStatus);
|
||||
}
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* @brief Accept() is called when user agree with entered data.
|
||||
*/
|
||||
virtual void accept();
|
||||
|
||||
private Q_SLOTS:
|
||||
/**
|
||||
* @brief Test current connection
|
||||
*/
|
||||
void testConnection();
|
||||
|
||||
void on_createConnLinkActivated();
|
||||
|
||||
private:
|
||||
bool validateAndApply();
|
||||
|
||||
// todo: may return nullptr
|
||||
/* example usage:
|
||||
auto uriWithStatus = getUriWithStatus();
|
||||
if (!uriWithStatus || !uriWithStatus->isOK()) {
|
||||
return;
|
||||
}
|
||||
auto uri = uriWithStatus->getValue();
|
||||
*/
|
||||
std::unique_ptr<MongoURIwithStatus> getUriWithStatus();
|
||||
|
||||
QLineEdit* _uriLineEdit;
|
||||
|
||||
/**
|
||||
* @brief Edited connection
|
||||
*/
|
||||
ConnectionSettings* _connection;
|
||||
ConnectionsDialog* _connectionsDialog;
|
||||
|
||||
std::unique_ptr<mongo::StatusWith<mongo::MongoURI>> _mongoUriWithStatus;
|
||||
bool _fromURI;
|
||||
};
|
||||
}
|
||||
@@ -6,9 +6,7 @@
|
||||
#include <QMessageBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDesktopWidget>
|
||||
#include <QSettings>
|
||||
#include <Qsci/qscilexerjavascript.h>
|
||||
|
||||
#include <mongo/client/dbclientinterface.h>
|
||||
|
||||
#include "robomongo/gui/editors/JSLexer.h"
|
||||
@@ -36,15 +34,7 @@ namespace Robomongo
|
||||
QSize size(screenGeometry.width() - horizontalMargin,
|
||||
screenGeometry.height() - verticalMargin);
|
||||
|
||||
QSettings settings("3T", "Robomongo");
|
||||
if (settings.contains("DocumentTextEditor/size"))
|
||||
{
|
||||
restoreWindowSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
resize(size);
|
||||
}
|
||||
resize(size);
|
||||
|
||||
setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
|
||||
|
||||
@@ -115,8 +105,6 @@ namespace Robomongo
|
||||
if (!validate())
|
||||
return;
|
||||
|
||||
saveWindowSettings();
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
@@ -139,8 +127,6 @@ namespace Robomongo
|
||||
return;
|
||||
}
|
||||
|
||||
saveWindowSettings();
|
||||
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
@@ -200,12 +186,6 @@ namespace Robomongo
|
||||
validate(false);
|
||||
}
|
||||
|
||||
void DocumentTextEditor::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
saveWindowSettings();
|
||||
QWidget::closeEvent(event);
|
||||
}
|
||||
|
||||
/*
|
||||
** Configure QsciScintilla query widget
|
||||
*/
|
||||
@@ -224,17 +204,4 @@ namespace Robomongo
|
||||
|
||||
_queryText->sciScintilla()->setStyleSheet("QFrame { background-color: rgb(73, 76, 78); border: 1px solid #c7c5c4; border-radius: 4px; margin: 0px; padding: 0px;}");
|
||||
}
|
||||
|
||||
void DocumentTextEditor::saveWindowSettings() const
|
||||
{
|
||||
QSettings settings("3T", "Robomongo");
|
||||
settings.setValue("DocumentTextEditor/size", size());
|
||||
}
|
||||
|
||||
void DocumentTextEditor::restoreWindowSettings()
|
||||
{
|
||||
QSettings settings("3T", "Robomongo");
|
||||
resize(settings.value("DocumentTextEditor/size").toSize());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,33 +28,16 @@ namespace Robomongo
|
||||
void setCursorPosition(int line, int column);
|
||||
|
||||
public Q_SLOTS:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
virtual void accept();
|
||||
virtual void reject();
|
||||
bool validate(bool silentOnSuccess = true);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onQueryTextChanged();
|
||||
void onValidateButtonClicked();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Reimplementing closeEvent in order to do some pre-close actions.
|
||||
*/
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
|
||||
private:
|
||||
void _configureQueryText();
|
||||
|
||||
/**
|
||||
* @brief Restore window settings from system registry
|
||||
*/
|
||||
void restoreWindowSettings();
|
||||
|
||||
/**
|
||||
* @brief Save window settings into system registry
|
||||
*/
|
||||
void saveWindowSettings() const;
|
||||
|
||||
const CollectionInfo _info;
|
||||
FindFrame *_queryText;
|
||||
bool _readonly;
|
||||
|
||||
@@ -1,243 +0,0 @@
|
||||
#include "robomongo/gui/dialogs/EulaDialog.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QMessageBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFile>
|
||||
#include <QSettings>
|
||||
#include <QLabel>
|
||||
#include <QTextBrowser>
|
||||
#include <QLineEdit>
|
||||
#include <QRadioButton>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QUrlQuery>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QDesktopWidget>
|
||||
|
||||
#include "robomongo/core/utils/QtUtils.h"
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
|
||||
EulaDialog::EulaDialog(QWidget *parent)
|
||||
: QWizard(parent)
|
||||
{
|
||||
setWindowTitle("EULA");
|
||||
|
||||
//// First page
|
||||
auto firstPage = new QWizardPage;
|
||||
|
||||
auto agreeButton = new QRadioButton("I agree");
|
||||
VERIFY(connect(agreeButton, SIGNAL(clicked()),
|
||||
this, SLOT(on_agreeButton_clicked())));
|
||||
|
||||
auto notAgreeButton = new QRadioButton("I don't agree");
|
||||
notAgreeButton->setChecked(true);
|
||||
VERIFY(connect(notAgreeButton, SIGNAL(clicked()),
|
||||
this, SLOT(on_notAgreeButton_clicked())));
|
||||
|
||||
auto radioButtonsLay = new QHBoxLayout;
|
||||
radioButtonsLay->setAlignment(Qt::AlignHCenter);
|
||||
radioButtonsLay->setSpacing(30);
|
||||
radioButtonsLay->addWidget(agreeButton);
|
||||
radioButtonsLay->addWidget(notAgreeButton);
|
||||
|
||||
auto textBrowser = new QTextBrowser;
|
||||
textBrowser->setOpenExternalLinks(true);
|
||||
textBrowser->setOpenLinks(true);
|
||||
QFile file(":gnu_gpl3_license.html");
|
||||
if (file.open(QFile::ReadOnly | QFile::Text))
|
||||
textBrowser->setText(file.readAll());
|
||||
|
||||
auto hline = new QFrame();
|
||||
hline->setFrameShape(QFrame::HLine);
|
||||
hline->setFrameShadow(QFrame::Sunken);
|
||||
|
||||
auto mainLayout1 = new QVBoxLayout();
|
||||
mainLayout1->addWidget(new QLabel("<h3>End-User License Agreement</h3>"));
|
||||
mainLayout1->addWidget(new QLabel(""));
|
||||
mainLayout1->addWidget(textBrowser);
|
||||
mainLayout1->addWidget(new QLabel(""));
|
||||
mainLayout1->addLayout(radioButtonsLay, Qt::AlignCenter);
|
||||
mainLayout1->addWidget(new QLabel(""));
|
||||
mainLayout1->addWidget(hline);
|
||||
|
||||
firstPage->setLayout(mainLayout1);
|
||||
|
||||
//// Second page
|
||||
auto secondPage = new QWizardPage;
|
||||
|
||||
auto nameLabel = new QLabel("<b>First Name:</b>");
|
||||
_nameEdit = new QLineEdit;
|
||||
auto lastNameLabel = new QLabel("<b>Last Name:</b>");
|
||||
_lastNameEdit = new QLineEdit;
|
||||
|
||||
auto emailLabel = new QLabel("<b>Email:</b>");
|
||||
_emailEdit = new QLineEdit;
|
||||
|
||||
auto buttomLabel = new QLabel("By submitting this form I agree to 3T Software Labs "
|
||||
"<a href='https://studio3t.com/privacy-policy'>Privacy Policy</a>.");
|
||||
buttomLabel->setOpenExternalLinks(true);
|
||||
|
||||
auto bodyLabel = new QLabel("\nShare your email address with us and we'll keep you "
|
||||
"up-to-date with updates from us and new features as they come out.");
|
||||
bodyLabel->setWordWrap(true);
|
||||
|
||||
auto mainLayout2 = new QGridLayout();
|
||||
mainLayout2->addWidget(new QLabel, 0, 0, 1, 2);
|
||||
mainLayout2->addWidget(new QLabel("<h3>Thank you for choosing Robomongo!</h3>"), 1, 0, 1, 2);
|
||||
mainLayout2->addWidget(bodyLabel, 2, 0 , 1, 2);
|
||||
mainLayout2->addWidget(new QLabel, 3, 0, 1, 2);
|
||||
mainLayout2->addWidget(nameLabel, 4, 0);
|
||||
mainLayout2->addWidget(_nameEdit, 4, 1);
|
||||
mainLayout2->addWidget(lastNameLabel, 5, 0);
|
||||
mainLayout2->addWidget(_lastNameEdit, 5, 1);
|
||||
mainLayout2->addWidget(emailLabel, 6, 0);
|
||||
mainLayout2->addWidget(_emailEdit, 6, 1);
|
||||
mainLayout2->addWidget(new QLabel, 7, 0, 1, 2);
|
||||
mainLayout2->addWidget(buttomLabel, 8, 0, 1, 2);
|
||||
|
||||
secondPage->setLayout(mainLayout2);
|
||||
|
||||
addPage(firstPage);
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
addPage(secondPage);
|
||||
#endif
|
||||
|
||||
//// Buttons
|
||||
setButtonText(QWizard::CustomButton1, tr("Back"));
|
||||
setButtonText(QWizard::CustomButton2, tr("Next"));
|
||||
setButtonText(QWizard::CustomButton3, tr("Finish"));
|
||||
|
||||
VERIFY(connect(button(QWizard::CustomButton1), SIGNAL(clicked()), this, SLOT(on_back_clicked())));
|
||||
VERIFY(connect(button(QWizard::CustomButton2), SIGNAL(clicked()), this, SLOT(on_next_clicked())));
|
||||
VERIFY(connect(button(QWizard::CustomButton3), SIGNAL(clicked()), this, SLOT(on_finish_clicked())));
|
||||
|
||||
setButtonLayout(QList<WizardButton>{ QWizard::Stretch, QWizard::CustomButton1, QWizard::CustomButton2,
|
||||
QWizard::CancelButton, QWizard::CustomButton3});
|
||||
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
button(QWizard::CustomButton1)->setDisabled(true);
|
||||
button(QWizard::CustomButton2)->setDisabled(true);
|
||||
button(QWizard::CustomButton3)->setDisabled(true);
|
||||
#else // linux
|
||||
button(QWizard::CustomButton1)->setHidden(true);
|
||||
button(QWizard::CustomButton2)->setHidden(true);
|
||||
button(QWizard::CustomButton3)->setDisabled(true);
|
||||
#endif
|
||||
|
||||
setWizardStyle(QWizard::ModernStyle);
|
||||
|
||||
QSettings const settings("3T", "Robomongo");
|
||||
if (settings.contains("EulaDialog/size")) {
|
||||
restoreWindowSettings();
|
||||
}
|
||||
else {
|
||||
auto const desktop = QApplication::desktop();
|
||||
auto const& mainScreenSize = desktop->availableGeometry(desktop->primaryScreen()).size();
|
||||
resize(mainScreenSize.width()*0.5, mainScreenSize.height()*0.6);
|
||||
}
|
||||
}
|
||||
|
||||
void EulaDialog::accept()
|
||||
{
|
||||
saveWindowSettings();
|
||||
|
||||
// Build post data and send
|
||||
postUserData();
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void EulaDialog::reject()
|
||||
{
|
||||
saveWindowSettings();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
void EulaDialog::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
saveWindowSettings();
|
||||
QWidget::closeEvent(event);
|
||||
}
|
||||
|
||||
void EulaDialog::on_agreeButton_clicked()
|
||||
{
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
button(QWizard::CustomButton2)->setEnabled(true);
|
||||
#else
|
||||
button(QWizard::CustomButton3)->setEnabled(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void EulaDialog::on_notAgreeButton_clicked()
|
||||
{
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
button(QWizard::CustomButton2)->setEnabled(false);
|
||||
#else
|
||||
button(QWizard::CustomButton3)->setEnabled(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void EulaDialog::on_next_clicked()
|
||||
{
|
||||
next();
|
||||
button(QWizard::CustomButton1)->setEnabled(true);
|
||||
button(QWizard::CustomButton2)->setEnabled(false);
|
||||
button(QWizard::CustomButton3)->setEnabled(true);
|
||||
}
|
||||
|
||||
void EulaDialog::on_back_clicked()
|
||||
{
|
||||
back();
|
||||
button(QWizard::CustomButton1)->setEnabled(false);
|
||||
button(QWizard::CustomButton2)->setEnabled(true);
|
||||
button(QWizard::CustomButton3)->setEnabled(false);
|
||||
}
|
||||
|
||||
void EulaDialog::on_finish_clicked()
|
||||
{
|
||||
accept();
|
||||
}
|
||||
|
||||
void EulaDialog::postUserData() const
|
||||
{
|
||||
if (_emailEdit->text().isEmpty())
|
||||
return;
|
||||
|
||||
// Build post data and send
|
||||
QJsonObject jsonStr {
|
||||
{ "email", _emailEdit->text() },
|
||||
{ "firstName", _nameEdit->text() },
|
||||
{ "lastName", _lastNameEdit->text() }
|
||||
};
|
||||
|
||||
QJsonDocument jsonDoc(jsonStr);
|
||||
QUrlQuery postData(jsonDoc.toJson());
|
||||
postData = QUrlQuery("rd=" + postData.toString(QUrl::FullyEncoded).toUtf8());
|
||||
|
||||
QNetworkRequest request(QUrl("https://rm-form.3t.io/"));
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
|
||||
auto networkManager = new QNetworkAccessManager;
|
||||
_reply = networkManager->post(request, postData.toString(QUrl::FullyEncoded).toUtf8());
|
||||
}
|
||||
|
||||
void EulaDialog::saveWindowSettings() const
|
||||
{
|
||||
QSettings settings("3T", "Robomongo");
|
||||
settings.setValue("EulaDialog/size", size());
|
||||
}
|
||||
|
||||
void EulaDialog::restoreWindowSettings()
|
||||
{
|
||||
QSettings settings("3T", "Robomongo");
|
||||
resize(settings.value("EulaDialog/size").toSize());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWizard>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QCheckBox;
|
||||
class QPushButton;
|
||||
class QDialogButtonBox;
|
||||
class QComboBox;
|
||||
class QNetworkReply;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
|
||||
class EulaDialog : public QWizard
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static const QSize minimumSize;
|
||||
|
||||
explicit EulaDialog(QWidget *parent = nullptr);
|
||||
|
||||
public Q_SLOTS:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void on_agreeButton_clicked();
|
||||
void on_notAgreeButton_clicked();
|
||||
void on_next_clicked();
|
||||
void on_back_clicked();
|
||||
void on_finish_clicked();
|
||||
|
||||
private:
|
||||
|
||||
// Send name, last name and email data of user to home server
|
||||
void postUserData() const;
|
||||
|
||||
/**
|
||||
* @brief Restore window settings from system registry
|
||||
*/
|
||||
void restoreWindowSettings();
|
||||
|
||||
/**
|
||||
* @brief Save window settings into system registry
|
||||
*/
|
||||
void saveWindowSettings() const;
|
||||
|
||||
QLineEdit* _nameEdit;
|
||||
QLineEdit* _lastNameEdit;
|
||||
QLineEdit* _emailEdit;
|
||||
|
||||
QByteArray _postData;
|
||||
mutable QNetworkReply* _reply;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
|
||||
namespace Robomongo
|
||||
{
|
||||
//const QSize ExportDialog::dialogSize = QSize(500, 250); // todo: remove
|
||||
|
||||
namespace
|
||||
{
|
||||
const QString defaultDir = "D:\\exports\\"; // Default location
|
||||
@@ -127,12 +129,12 @@ namespace Robomongo
|
||||
VERIFY(connect(_formatComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_formatComboBox_change(int))));
|
||||
|
||||
_fieldsLabel = new QLabel("Fields:");
|
||||
_fields = new QLineEdit; // todo: use textedit
|
||||
_fields = new QLineEdit; // todo: make textedit
|
||||
// Initially hidden
|
||||
_fieldsLabel->setHidden(true);
|
||||
_fields->setHidden(true);
|
||||
|
||||
_query = new QLineEdit("{}"); // todo: JSON frame can be used
|
||||
_query = new QLineEdit("{}"); // todo: can use JSON frame
|
||||
_outputFileName = new QLineEdit;
|
||||
_outputDir = new QLineEdit;
|
||||
_browseButton = new QPushButton("...");
|
||||
@@ -152,7 +154,7 @@ namespace Robomongo
|
||||
|
||||
// Attempt to fix issue for Windows High DPI button height is slightly taller than other widgets
|
||||
#ifdef Q_OS_WIN
|
||||
_browseButton->setMaximumHeight(HighDpiConstants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
_browseButton->setMaximumHeight(HighDpiContants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
#endif
|
||||
auto outputsInnerLay = new QGridLayout;
|
||||
outputsInnerLay->addWidget(new QLabel("Format:"), 0, 0);
|
||||
@@ -244,7 +246,7 @@ namespace Robomongo
|
||||
layout->addLayout(hButtonBoxlayout);
|
||||
setLayout(layout);
|
||||
|
||||
// todo: move to a function
|
||||
// todo: move to function
|
||||
// Help user filling inputs automatically
|
||||
auto date = QDateTime::currentDateTime().toString("dd.MM.yyyy");
|
||||
auto time = QDateTime::currentDateTime().toString("hh.mm.ss");
|
||||
@@ -274,6 +276,13 @@ namespace Robomongo
|
||||
//_inputLabel->setText(text);
|
||||
}
|
||||
|
||||
// todo: remove
|
||||
void ExportDialog::setInputText(const QString &text)
|
||||
{
|
||||
//_inputEdit->setText(text);
|
||||
//_inputEdit->selectAll();
|
||||
}
|
||||
|
||||
void ExportDialog::accept()
|
||||
{
|
||||
QString mongoExport = "D:\\mongo_export\\bin\\mongoexport.exe";
|
||||
@@ -340,7 +349,17 @@ namespace Robomongo
|
||||
|
||||
void ExportDialog::ui_itemDoubleClicked(QTreeWidgetItem *item, int column)
|
||||
{
|
||||
//auto collectionItem = dynamic_cast<ExplorerCollectionTreeItem*>(item);
|
||||
//if (collectionItem) {
|
||||
// AppRegistry::instance().app()->openShell(collectionItem->collection());
|
||||
// return;
|
||||
//}
|
||||
|
||||
// todo
|
||||
//auto dbTreeItem = dynamic_cast<ExplorerDatabaseTreeItem*>(item);
|
||||
//if (dbTreeItem) {
|
||||
// dbTreeItem->applySettingsForExportDialog();
|
||||
//}
|
||||
}
|
||||
|
||||
void ExportDialog::on_browseButton_clicked()
|
||||
@@ -425,7 +444,6 @@ namespace Robomongo
|
||||
_exportOutput->setText("Export Failed.\n");
|
||||
_exportOutput->append("Output:\n" + _mongoExportOutputStr);
|
||||
}
|
||||
|
||||
_exportOutput->moveCursor(QTextCursor::Start);
|
||||
}
|
||||
|
||||
@@ -446,7 +464,6 @@ namespace Robomongo
|
||||
_exportOutput->setText("Error: \"mongoexport\" process failed. Error code: "
|
||||
+ QString::number(error));
|
||||
}
|
||||
|
||||
_exportOutput->moveCursor(QTextCursor::Start);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,20 +20,6 @@ namespace Robomongo
|
||||
{
|
||||
class Indicator;
|
||||
|
||||
/**
|
||||
* @brief This class is not finished, it is still under development.
|
||||
* Currently export is disabled in the GUI. If enabled in GUI, export
|
||||
* will work with current code. However, the code is unfinished;
|
||||
* it needs to finished, reviewed and tested.
|
||||
* Currently, there is support for simultaneous export which can be done
|
||||
* on multiple export dialogs without blocking each other or main window.
|
||||
* So user can still work while multiple export dialogs are doing export.
|
||||
* This achieved by the assumption that there will be usable export executable for
|
||||
* Robomongo to use. Currently, this location is hard coded as
|
||||
* "D:\\mongo_export\\bin\\mongoexport.exe". One of the next actions will be
|
||||
* to design the location of mongoexport which should be cross-platform,
|
||||
* generic and not hard coded.
|
||||
*/
|
||||
class ExportDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -46,10 +32,12 @@ namespace Robomongo
|
||||
|
||||
public:
|
||||
explicit ExportDialog(QString const& dbName, QString const& collName, QWidget *parent = 0);
|
||||
//QString databaseName() const;
|
||||
void setOkButtonText(const QString &text);
|
||||
void setInputLabelText(const QString &text);
|
||||
void setInputText(const QString &text);
|
||||
enum { maxLenghtName = 60 };
|
||||
//const static QSize dialogSize;
|
||||
|
||||
public Q_SLOTS:
|
||||
virtual void accept();
|
||||
@@ -65,7 +53,7 @@ namespace Robomongo
|
||||
void on_viewOutputLink(QString);
|
||||
|
||||
private:
|
||||
// todo: remove if unused
|
||||
// todo: remove
|
||||
Indicator *createDatabaseIndicator(const QString &database);
|
||||
Indicator *createCollectionIndicator(const QString &collection);
|
||||
|
||||
|
||||
@@ -152,9 +152,9 @@ namespace Robomongo
|
||||
#endif
|
||||
// Attempt to fix the issue for Windows High DPI button height is slightly taller than other widgets
|
||||
#ifdef Q_OS_WIN
|
||||
_passwordEchoModeButton->setMaximumHeight(HighDpiConstants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
_passphraseEchoModeButton->setMaximumHeight(HighDpiConstants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
_selectPrivateFileButton->setMaximumHeight(HighDpiConstants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
_passwordEchoModeButton->setMaximumHeight(HighDpiContants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
_passphraseEchoModeButton->setMaximumHeight(HighDpiContants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
_selectPrivateFileButton->setMaximumHeight(HighDpiContants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -189,10 +189,10 @@ namespace Robomongo
|
||||
|
||||
// Attempt to fix issue for Windows High DPI button height is slightly taller than other widgets
|
||||
#ifdef Q_OS_WIN
|
||||
_caFileBrowseButton->setMaximumHeight(HighDpiConstants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
_pemFileBrowseButton->setMaximumHeight(HighDpiConstants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
_pemPassShowButton->setMaximumHeight(HighDpiConstants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
_crlFileBrowseButton->setMaximumHeight(HighDpiConstants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
_caFileBrowseButton->setMaximumHeight(HighDpiContants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
_pemFileBrowseButton->setMaximumHeight(HighDpiContants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
_pemPassShowButton->setMaximumHeight(HighDpiContants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
_crlFileBrowseButton->setMaximumHeight(HighDpiContants::WIN_HIGH_DPI_BUTTON_HEIGHT);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -20,27 +20,18 @@
|
||||
<file>scripts/esprima.js</file>
|
||||
<file>scripts/uuidhelpers.js</file>
|
||||
<file>icons/maximize.gif</file>
|
||||
<file>icons/undock.png</file>
|
||||
<file>icons/dock.png</file>
|
||||
<file>icons/maximize.png</file>
|
||||
<file>icons/minimize.png</file>
|
||||
<file>icons/text_16x16.png</file>
|
||||
<file>icons/tree_16x16.png</file>
|
||||
<file>icons/rotate_16x16.png</file>
|
||||
<file>icons/close_16x16.png</file>
|
||||
<file>icons/close_hover_16x16.png</file>
|
||||
<file>icons/close_2_16x16.png</file>
|
||||
<file>icons/close_hover_16x16_original.png</file>
|
||||
<file>icons/text2_16x16.png</file>
|
||||
<file>icons/mongodb_16x16.png</file>
|
||||
<file>icons/mongodb_icon_for_MAC.png</file>
|
||||
<file>icons/connect_24x24.png</file>
|
||||
<file>icons/server_16x16.png</file>
|
||||
<file>icons/server_primary_16x16.png</file>
|
||||
<file>icons/server_secondary_16x16.png</file>
|
||||
<file>icons/server_imported_16x16.png</file>
|
||||
<file>icons/replica_set_16x16.png</file>
|
||||
<file>icons/replica_set_offline_16x16.png</file>
|
||||
<file>icons/execute_24x24.png</file>
|
||||
<file>icons/main_window_icon_old.png</file>
|
||||
<file>icons/logo-256x256.png</file>
|
||||
@@ -73,11 +64,5 @@
|
||||
<file>icons/show_64x64.png</file>
|
||||
<file>icons/export_64x64.png</file>
|
||||
<file>icons/import_64x64.png</file>
|
||||
<file>icons/plus_sign.png</file>
|
||||
<file>icons/minus_sign.png</file>
|
||||
<file>icons/delete.png</file>
|
||||
<file>icons/delete_red_color.png</file>
|
||||
<file>icons/delete_mouse_hovered.png</file>
|
||||
<file>icons/welcome_tab_icon.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
|
Before Width: | Height: | Size: 518 B |
|
Before Width: | Height: | Size: 334 B |
|
Before Width: | Height: | Size: 550 B |
|
Before Width: | Height: | Size: 189 B |
|
Before Width: | Height: | Size: 388 B |
|
Before Width: | Height: | Size: 384 B |
|
Before Width: | Height: | Size: 168 B |
|
Before Width: | Height: | Size: 509 B |
|
Before Width: | Height: | Size: 192 B |
|
Before Width: | Height: | Size: 446 B After Width: | Height: | Size: 511 B |
|
Before Width: | Height: | Size: 407 B |
|
Before Width: | Height: | Size: 397 B |