Compare commits

...

52 Commits

Author SHA1 Message Date
oguzhankoral e05ae7694b Merge branch 'oguzhan/dui3' into oguzhan/dui3-instant-message-sender 2023-08-16 17:02:10 +03:00
oguzhankoral ed19e1e227 Send message from sender card 2023-08-16 14:40:30 +03:00
oguzhankoral c770eef923 WIP: instant message sender 2023-08-16 14:21:51 +03:00
oguzhankoral 1812c9ec8d Correct send data 2023-08-14 16:42:08 +03:00
oguzhankoral 533fdecc80 Real send via DUI3 2023-08-10 13:45:59 +03:00
oguzhankoral 954aaa07e3 Trigger sendersExpired when objects modified 2023-08-08 19:33:01 +03:00
oguzhankoral 9080882ee7 Use AddModel action for updateModel command 2023-08-08 16:16:40 +03:00
oguzhankoral d09c6654a5 Place binding classes into folder 2023-08-08 16:05:30 +03:00
oguzhankoral 2a377fee55 Enable error catch for command 2023-08-08 16:05:10 +03:00
oguzhankoral 061ae03c51 Update model card 2023-08-08 12:21:13 +03:00
oguzhankoral 52725e7260 Add type discriminator 2023-08-08 12:00:20 +03:00
oguzhankoral 329dbb868a Reorganize send bindings 2023-08-08 11:59:57 +03:00
oguzhankoral e6a57ec1ed Split account binding from base 2023-08-08 10:45:55 +03:00
oguzhankoral a0aa6359d9 Align with Dim's works 2023-08-04 10:16:44 +03:00
oguzhankoral d31c712a96 WIP: selection bindings - add cards to model 2023-08-04 00:45:10 +03:00
oguzhankoral 9f1e525860 WIP: filters 2023-08-02 20:53:10 +03:00
oguzhankoral 815899da8c Convert tag colors to hex 2023-07-31 17:57:33 +03:00
oguzhankoral ef9a203c26 Get default filters 2023-07-30 00:31:52 +03:00
oguzhankoral ee13ca3bb8 Get model state and send filter for sketchup 2023-07-29 10:57:54 +03:00
oguzhankoral 24cfab6aac WIP: connector configs 2023-07-26 04:14:08 +03:00
oguzhankoral f4d79f23c1 Implement config_binding 2023-07-25 22:16:28 +03:00
oguzhankoral f88ba994f6 Introduce ruby traverse_and_construct 2023-07-25 14:48:52 +03:00
oguzhankoral 47414080ee Send-Receive operations test via ruby 2023-07-25 14:48:52 +03:00
oguzhankoral f4f5f2b82f Remove test bridge.js 2023-07-25 14:48:52 +03:00
oguzhankoral 2b11afcbd9 Unit test for send operation 2023-07-25 14:48:52 +03:00
oguzhankoral 6e28df0867 Enable collect preferences 2023-07-25 14:48:52 +03:00
oguzhankoral a5cbfaf65b Emit only documentChanged instead of passing data 2023-07-25 14:48:52 +03:00
oguzhankoral 77af361e1c Rename views to bindings 2023-07-25 14:48:52 +03:00
oguzhankoral 007d15bf51 Report errors to UI 2023-07-25 14:48:52 +03:00
oguzhankoral cd0c237ad6 Resolve triggerEvent 2023-07-25 14:48:52 +03:00
oguzhankoral 6a40e3f317 Implement test bindings 2023-07-25 14:48:52 +03:00
oguzhankoral bceb18fc3c Create random sketchup binding 2023-07-25 14:48:52 +03:00
oguzhankoral e1de48f831 Implement on_document_changed action 2023-07-25 14:48:52 +03:00
oguzhankoral 9459362a3b Add command for get document info 2023-07-25 14:48:52 +03:00
oguzhankoral 8e17b26e00 Remove get_commands action and command 2023-07-25 14:48:52 +03:00
oguzhankoral fb48db3a05 Apply same dialog-view relationship to legacy UI 2023-07-25 14:48:51 +03:00
oguzhankoral b4fb578bff Control views via dialog 2023-07-25 14:48:51 +03:00
oguzhankoral e5cf3b7d49 Remove unnecssary init from view 2023-07-25 14:48:51 +03:00
oguzhankoral fcd25605a6 Collect command names from related view for SketchupBridge 2023-07-25 14:48:51 +03:00
oguzhankoral a3fd1605ac Pass view to commands 2023-07-25 14:48:51 +03:00
oguzhankoral 674ac985f4 Send messages to correct view/binding 2023-07-25 14:48:51 +03:00
oguzhankoral e8576f3811 Solve missing resolve_id arguments for commands and actions 2023-07-25 14:48:51 +03:00
oguzhankoral 0fa3ebd51b Run legacy and dui3 at the same time 2023-07-25 14:48:51 +03:00
oguzhankoral acad57d1d7 Pass resolve id from arguments 2023-07-25 14:48:51 +03:00
oguzhankoral f268ca144f Replace Bridge with inhouse resolve_id solution 2023-07-25 14:48:51 +03:00
oguzhankoral a8e5032d9d Pass serialized accounts data as json object 2023-07-25 14:48:51 +03:00
oguzhankoral 4e5b8a4a6f Pass correct request id for getAccounts 2023-07-25 14:48:51 +03:00
oguzhankoral 375dcd05b3 Request id temp hack 2023-07-25 14:48:51 +03:00
oguzhankoral 622d56f965 Add get commands 2023-07-25 14:48:51 +03:00
oguzhankoral d6c780e195 Add bridge sample 2023-07-25 14:48:51 +03:00
oguzhankoral 0b202c7084 Check correct dui3 id ui controller 2023-07-25 14:48:51 +03:00
oguzhankoral 3e4bc9d81f Add new dialog for dui3 2023-07-25 14:48:51 +03:00
118 changed files with 2278 additions and 184 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

@@ -7,6 +7,7 @@ require_relative '../constants/path_constants'
module SpeckleConnector
# Accounts to communicate with models on user's account.
module Accounts
# Load accounts from user's app data.
def self.load_accounts
db_path = SPECKLE_ACCOUNTS_DB_PATH
unless File.exist?(db_path)
@@ -23,9 +24,21 @@ module SpeckleConnector
rows.map { |row| JSON.parse(row[1]) }
end
def self.get_account_by_id(id)
accounts = load_accounts
accounts.select { |acc| acc['id'] == id }[0]
end
# Default account on the user computer.
def self.default_account
accounts = load_accounts
accounts.select { |acc| acc['isDefault'] }[0] || accounts[0]
end
# Try to get local server account for debug/test purposes.
def self.try_get_local_server_account
accounts = load_accounts
accounts.select { |acc| acc['serverInfo']['url'].include?('localhost') }[0] || nil
end
end
end
@@ -15,7 +15,7 @@ module SpeckleConnector
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def update_state(state)
state = DeactivateDiffing.update_state(state, {})
state = DeactivateDiffing.update_state(state, nil, {})
puts "Diffing activated for #{@stream_id}"
speckle_entities = state.speckle_state.speckle_entities
invalid_speckle_entities = speckle_entities.select do |_id, entity|
@@ -0,0 +1,33 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../cards/send_card'
require_relative '../../filters/send/everything_filter'
require_relative '../../filters/send/selection_filter'
require_relative '../../filters/send_filters'
require_relative '../../sketchup_model/dictionary/send_card_dictionary_handler'
module SpeckleConnector
module Actions
# Action to add send card.
class AddModel < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id, data)
send_filter = Filters::SendFilters.get_filter_from_ui_data(data['sendFilter'])
# Init card and add to the state
send_card = Cards::SendCard.new(data['id'], data['accountId'], data['projectId'], data['modelId'],
send_filter, {})
SketchupModel::Dictionary::SendCardDictionaryHandler
.save_card_to_model(send_card, state.sketchup_state.sketchup_model)
new_speckle_state = state.speckle_state.with_send_card(send_card)
state = state.with_speckle_state(new_speckle_state)
# Resolve promise
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('addSendCard', js_script)
end
end
end
end
@@ -0,0 +1,30 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../cards/send_card'
require_relative '../../filters/send_filters'
require_relative '../../sketchup_model/dictionary/send_card_dictionary_handler'
module SpeckleConnector
module Actions
# Add model to document state.
class AddModelToDocumentState < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id, model)
puts model.to_json
send_filter = Filters::SendFilters.get_filter_from_ui_data(model['sendFilter'])
send_card = Cards::SendCard.new(model['id'], model['accountId'], model['projectId'], model['modelId'], send_filter, {})
SketchupModel::Dictionary::SendCardDictionaryHandler
.save_card_to_model(send_card, state.sketchup_state.sketchup_model)
new_speckle_state = state.speckle_state.with_send_card(send_card)
state = state.with_speckle_state(new_speckle_state)
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('addModelToDocumentState', js_script)
end
end
end
end
@@ -0,0 +1,40 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../filters/send_filters'
require_relative '../../sketchup_model/dictionary/send_card_dictionary_handler'
module SpeckleConnector
module Actions
# Gets document state.
class GetDocumentState < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id)
send_cards_hash = SketchupModel::Dictionary::SendCardDictionaryHandler
.get_cards_from_dict(state.sketchup_state.sketchup_model)
send_cards = send_cards_hash.collect do |id, card|
filter = Filters::SendFilters.get_filter_from_document(card['sendFilter'])
send_card = Cards::SendCard.new(id, card['account_id'], card['project_id'], card['model_id'], filter, {})
new_speckle_state = state.speckle_state.with_send_card(send_card)
state = state.with_speckle_state(new_speckle_state)
{
id: send_card.id,
accountId: send_card.account_id,
projectId: send_card.project_id,
modelId: send_card.model_id,
sendFilter: send_card.send_filter,
typeDiscriminator: send_card.type_discriminator
}
end
model_state = { models: send_cards }
js_script = "baseBinding.receiveResponse('#{resolve_id}', #{model_state.to_json})"
state.with_add_queue_js_command('getDocumentState', js_script)
end
end
end
end
@@ -0,0 +1,38 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../filters/send_filters'
require_relative '../../sketchup_model/dictionary/send_card_dictionary_handler'
module SpeckleConnector
module Actions
# Gets model state.
class GetModelState < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id)
send_cards_hash = SketchupModel::Dictionary::SendCardDictionaryHandler
.get_cards_from_dict(state.sketchup_state.sketchup_model)
send_cards = send_cards_hash.collect do |id, card|
filters = Filters::SendFilters.get_filters_from_model(card['filters'])
send_card = Cards::SendCard.new(id, card['account_id'], card['project_id'], card['model_id'], filters)
new_speckle_state = state.speckle_state.with_send_card(send_card)
state = state.with_speckle_state(new_speckle_state)
{
accountId: send_card.account_id,
projectId: send_card.project_id,
modelId: send_card.model_id,
filters: send_card.filters
}
end
model_state = { sendCards: send_cards }
js_script = "baseBinding.receiveResponse('#{resolve_id}', #{model_state.to_json})"
state.with_add_queue_js_command('getModelState', js_script)
end
end
end
end
@@ -0,0 +1,19 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../filters/send_filters'
module SpeckleConnector
module Actions
# Action to get send filter.
class GetSendFilters < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id)
default_filters = Filters::SendFilters.get_default(state.sketchup_state.sketchup_model)
js_script = "sendBinding.receiveResponse('#{resolve_id}', #{default_filters.to_json})"
state.with_add_queue_js_command('getSendFilter', js_script)
end
end
end
end
@@ -0,0 +1,20 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../sketchup_model/dictionary/send_card_dictionary_handler'
module SpeckleConnector
module Actions
# Action to update send filter.
class UpdateSendFilter < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id, data, value)
SketchupModel::Dictionary::SendCardDictionaryHandler.update_filter(state.sketchup_state.sketchup_model, data, value)
js_script = "sendBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('updateSendFilter', js_script)
end
end
end
end
@@ -9,7 +9,7 @@ module SpeckleConnector
class ClearMapperSource < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, _data)
def self.update_state(state, _resolve_id, _data)
new_speckle_state = state.speckle_state.with_removed_mapper_source
erase_levels(state)
state.with_speckle_state(new_speckle_state)
@@ -11,7 +11,7 @@ module SpeckleConnector
class ClearMappingsFromTable < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, data)
def self.update_state(state, _resolve_id, data)
# Flat entities to clear mappings
flat_entities = SketchupModel::Query::Entity.flat_entities(state.sketchup_state.sketchup_model.entities)
@@ -10,7 +10,7 @@ module SpeckleConnector
class CollectPreferences < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, _data)
def self.update_state(state, _resolve_id, _data)
state.with_add_queue('collectPreferences', state.user_state.preferences.to_json, [])
end
end
@@ -8,7 +8,7 @@ module SpeckleConnector
class CollectVersions < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, _data)
def self.update_state(state, _resolve_id, _data)
versions = {
sketchup: Sketchup.version.to_i,
speckle: SpeckleConnector::CONNECTOR_VERSION
@@ -0,0 +1,22 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Action to get config.
class GetConfig < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id)
# Previously it was stored in user state
# config = state.user_state.preferences.to_json
config = {
darkTheme: state.user_state.user_preferences[:dark_theme]
}
js_script = "configBinding.receiveResponse('#{resolve_id}', #{config.to_json})"
state.with_add_queue_js_command('getConfig', js_script)
end
end
end
end
@@ -0,0 +1,26 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../user_preferences_updated'
module SpeckleConnector
module Actions
# Action to update config.
class UpdateConfig < Action
KEY_VALUES = {
'darkTheme' => 'dark_theme'
}.freeze
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id, config)
config.each do |key, value|
state = Actions::UserPreferencesUpdated.new('configSketchup', KEY_VALUES[key], value).update_state(state)
end
js_script = "configBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('updateConfig', js_script)
end
end
end
end
@@ -8,7 +8,7 @@ module SpeckleConnector
class DeactivateDiffing < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, _data)
def self.update_state(state, _resolve_id, _data)
puts 'Diffing deactivated!'
speckle_entities = state.speckle_state.speckle_entities
diffing_activated_speckle_entities = speckle_entities.reject do |_id, entity|
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require_relative 'event_action'
require_relative 'on_document_changed'
require_relative '../load_sketchup_model'
require_relative '../collect_preferences'
@@ -25,7 +26,8 @@ module SpeckleConnector
# Action to let UI to render itself with new preferences state
# TODO: Later UI should be updated if any stream is invalid after
# we collected speckle_entities appropriately
CollectPreferences.update_state(new_state, {})
new_state = CollectPreferences.update_state(new_state, nil, {})
OnDocumentChanged.update_state(new_state)
end
end
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require_relative 'event_action'
require_relative '../../actions/send_actions/send_card_expiration_check'
require_relative '../../sketchup_model/utils/face_utils'
require_relative '../../constants/dict_constants'
@@ -26,19 +27,23 @@ module SpeckleConnector
def self.update_state(state, event_data)
speckle_state = state.speckle_state
modified_entity = event_data[0][1]
if modified_entity.is_a?(Sketchup::Face)
path = state.sketchup_state.sketchup_model.active_path
modified_faces = SketchupModel::Utils::FaceUtils.near_faces(modified_entity.edges)
path_objects = path.nil? ? [] : path + path.collect(&:definition)
parent_ids = path_objects.collect(&:persistent_id)
ids_to_invalidate = modified_faces.collect(&:persistent_id) + parent_ids
entities_to_invalidate = speckle_entities_to_invalidate(speckle_state, ids_to_invalidate)
new_speckle_state = invalidate_speckle_entities(speckle_state, entities_to_invalidate)
# This is the place we can send information to UI for diffing check
diffing = state.user_state.preferences[:user][:diffing]
new_speckle_state = new_speckle_state.with_invalid_streams_queue if diffing
return state.with_speckle_state(new_speckle_state)
end
modified_entities = event_data.collect { |data| data[1] }
new_speckle_state = state.speckle_state.with_changed_object_ids(modified_entities.collect(&:persistent_id))
state = state.with_speckle_state(new_speckle_state)
state = Actions::SendCardExpirationCheck.update_state(state)
# if modified_entity.is_a?(Sketchup::Face)
# path = state.sketchup_state.sketchup_model.active_path
# modified_faces = SketchupModel::Utils::FaceUtils.near_faces(modified_entity.edges)
# path_objects = path.nil? ? [] : path + path.collect(&:definition)
# parent_ids = path_objects.collect(&:persistent_id)
# ids_to_invalidate = modified_faces.collect(&:persistent_id) + parent_ids
# entities_to_invalidate = speckle_entities_to_invalidate(speckle_state, ids_to_invalidate)
# new_speckle_state = invalidate_speckle_entities(speckle_state, entities_to_invalidate)
# # This is the place we can send information to UI for diffing check
# diffing = state.user_state.preferences[:user][:diffing]
# new_speckle_state = new_speckle_state.with_invalid_streams_queue if diffing
# return state.with_speckle_state(new_speckle_state)
# end
state
end
@@ -0,0 +1,15 @@
# frozen_string_literal: true
module SpeckleConnector
module Actions
# Triggers whenever document has changed.
class OnDocumentChanged < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state)
js_command = "baseBinding.emit('documentChanged')"
state.with_add_queue_js_command('documentChanged', js_command)
end
end
end
end
@@ -2,6 +2,7 @@
require_relative 'event_action'
require_relative '../mapper_selection_changed'
require_relative '../selection_actions/get_selection'
require_relative '../../mapper/category/revit_category'
require_relative '../../sketchup_model/reader/speckle_entities_reader'
require_relative '../../sketchup_model/reader/mapper_reader'
@@ -20,9 +21,11 @@ module SpeckleConnector
# Get sketchup selection
sketchup_selection = state.sketchup_state.sketchup_model.selection
Actions::GetSelection.update_state(state)
# Collect and return mapper selection info.
# Later we can add more selection info for different scopes.
MapperSelectionChanged.new(sketchup_selection).update_state(state)
# MapperSelectionChanged.new(sketchup_selection).update_state(state)
end
end
end
@@ -0,0 +1,21 @@
# frozen_string_literal: true
require_relative 'action'
require_relative '../accounts/accounts'
require_relative 'load_saved_streams'
module SpeckleConnector
module Actions
# Action to initialize local accounts from database.
class GetAccounts < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id)
puts 'Initialisation of Speckle accounts requested by plugin'
accounts_data = state.speckle_state.accounts
js_script = "accountsBinding.receiveResponse('#{resolve_id}', #{accounts_data.to_json})"
state.with_add_queue_js_command('getAccounts', js_script)
end
end
end
end
@@ -0,0 +1,22 @@
# frozen_string_literal: true
require_relative 'action'
module SpeckleConnector
module Actions
# Get document info.
class GetDocumentInfo < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id)
document_info = {
location: state.sketchup_state.sketchup_model.path,
name: state.sketchup_state.sketchup_model.name,
id: state.sketchup_state.sketchup_model.guid
}
js_command = "baseBinding.receiveResponse('#{resolve_id}', #{document_info.to_json})"
state.with_add_queue_js_command('getDocumentInfo', js_command)
end
end
end
end
@@ -0,0 +1,18 @@
# frozen_string_literal: true
require_relative 'action'
module SpeckleConnector
module Actions
# Get source app name.
class GetSourceAppName < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id)
js_command = "baseBinding.receiveResponse('#{resolve_id}', 'Sketchup')"
puts js_command
state.with_add_queue_js_command('getSourceAppName', js_command)
end
end
end
end
@@ -0,0 +1,31 @@
# frozen_string_literal: true
module SpeckleConnector
module Actions
# Action to return error message to UI.
class HandleError < Action
# @param error [String] error
# @param view_name [String] name of the view (binding)
# @param action [Action] action that error happened
# @param parameters [Array<String>] arguments
def initialize(error, view_name, action, parameters)
super()
@error = error
@view_name = view_name
@action = action
@args = parameters
end
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def update_state(state)
error_message = "Error: #{@error}\nBinding: #{@view_name}\nArgs: #{@args}\n"
error = {
error: error_message
}
js_error_script = "#{@view_name}.receiveResponse('#{@args.first}', #{error.to_json})"
state.with_add_queue_js_command("error_#{@view_name}", js_error_script)
end
end
end
end
@@ -10,7 +10,7 @@ module SpeckleConnector
class HideMappingsFromTable < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, data)
def self.update_state(state, _resolve_id, data)
# Flat entities to clear mappings
flat_entities = SketchupModel::Query::Entity.flat_entities(state.sketchup_state.sketchup_model.entities)
@@ -10,7 +10,7 @@ module SpeckleConnector
class InitLocalAccounts < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, _data)
def self.update_state(state, _request_id, _data)
puts 'Initialisation of Speckle accounts requested by plugin'
accounts_data = state.speckle_state.accounts
state.with_add_queue('loadAccounts', accounts_data.to_json, [])
@@ -14,7 +14,7 @@ module SpeckleConnector
class InitializeSpeckle < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, observers)
def self.update_state(state, observers, instant_message_sender)
attach_app_observer!(observers[APP_OBSERVER])
accounts = SpeckleConnector::Accounts.load_accounts
speckle_state = States::SpeckleState.new(accounts, observers, {}, {})
@@ -22,7 +22,8 @@ module SpeckleConnector
sketchup_state = States::SketchupState.new(Sketchup.active_model)
preferences = Preferences.read_preferences(sketchup_state.sketchup_model)
user_state_with_preferences = state.user_state.with_preferences(preferences)
state = States::State.new(user_state_with_preferences, speckle_state, sketchup_state, false)
state = States::State.new(user_state_with_preferences, speckle_state, sketchup_state,
false, &instant_message_sender)
# This is where we attach observers to related model objects like selection, entities..
Actions::LoadSketchupModel.update_state(state, sketchup_state.sketchup_model)
end
@@ -14,7 +14,7 @@ module SpeckleConnector
# rubocop:disable Metrics/MethodLength
# rubocop:disable Metrics/PerceivedComplexity
# rubocop:disable Metrics/CyclomaticComplexity
def self.update_state(state, data)
def self.update_state(state, _resolve_id, data)
sketchup_model = state.sketchup_state.sketchup_model
# Hide all entities first
@@ -8,7 +8,7 @@ module SpeckleConnector
class LoadSavedStreams < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, _data)
def self.update_state(state, _request_id, _data)
(saved_streams = state.sketchup_state.sketchup_model
.attribute_dictionary('Speckle', true)['saved_streams']) or []
state.with_add_queue('setSavedStreams', saved_streams, [])
@@ -9,7 +9,7 @@ module SpeckleConnector
class MappedEntitiesUpdated < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, _data = nil)
def self.update_state(state, _resolve_id = nil, _data = nil)
mapped_entities = SketchupModel::Reader::MapperReader
.mapped_entity_details(state.speckle_state.speckle_mapper_state.mapped_entities.values.to_a)
@@ -0,0 +1,18 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Action to let sketchup know receive from server is finished..
class AfterReceive < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id, stream_id, root_id)
puts "receive finished for: #{root_id}"
js_script = "sketchupReceiveBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('afterReceive', js_script)
end
end
end
end
@@ -0,0 +1,18 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Action to let sketchup know receive will be started.
class BeforeReceive < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id, stream_id, root_id)
puts "receive started for: #{root_id}"
js_script = "sketchupReceiveBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('beforeReceive', js_script)
end
end
end
end
@@ -0,0 +1,91 @@
# frozen_string_literal: true
require 'json'
require_relative '../action'
require_relative '../../convertors/units'
require_relative '../../convertors/to_native'
module SpeckleConnector
module Actions
# Clear mappings for selected entities.
class ReceiveSingleObject < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id, stream_id, root_id, speckle_objects)
puts "object receive #{speckle_objects.length}"
buffer = speckle_objects.collect { |obj| [obj['id'], obj] }.to_h
t_0 = Time.now.to_f
root_obj = traverse_and_construct(speckle_objects.first, buffer)
puts root_obj
puts "Elapsed traverse and construct #{Time.now.to_f - t_0}"
# File.open("#{ENV['HOME']}/OneDrive/Masaüstü/root.json", 'w') do |f|
# f.write(JSON.pretty_generate(root_obj))
# end
# converter = Converters::ToNative.new(state, stream_id, 'test', 'testt', 'test')
# state = converter.receive_commit_object(root_obj)
js_script = "sketchupReceiveBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('receiveObject', js_script)
end
def self.traverse_and_construct(obj, buffer)
return if obj.nil?
return obj if !obj.is_a?(Hash) && !obj.is_a?(Array)
# Handle arrays
if obj.is_a?(Array) && !obj.empty?
arr = handle_array(buffer, obj)
# De-chunk, if array is a set of datachunk, flat them into single data chunk.
arr = try_dechunk(arr)
return arr
end
# Handle object
obj = handle_hash(buffer, obj)
return obj
rescue StandardError => e
puts "#{e} -> #{obj}"
return nil
end
def self.handle_array(buffer, obj)
arr = []
obj.collect do |element|
next if element.nil?
deref = element.is_a?(Hash) && !element['referencedId'].nil? ? buffer[element['referencedId']] : element
arr.append(traverse_and_construct(deref, buffer))
end
arr
end
def self.try_dechunk(arr)
if arr[0].is_a?(Hash) && !arr[0]['speckle_type'].nil? && arr[0]['speckle_type'].downcase.include?('datachunk')
sum_arr = []
arr.each do |chunk|
sum_arr += chunk['data']
end
sum_arr
else
arr
end
end
def self.handle_hash(buffer, obj)
obj.each do |prop, value|
next if value.nil? || (!value.is_a?(Hash) && !value.is_a?(Array))
obj[prop] = buffer[value['referencedId']] if value.is_a?(Hash) && value['referencedId']
obj[prop] = traverse_and_construct(obj[prop], buffer)
end
obj
end
end
end
end
@@ -3,13 +3,14 @@
require_relative 'action'
require_relative '../convertors/units'
require_relative '../convertors/to_native'
require_relative '../operations/receive'
module SpeckleConnector
module Actions
# Action to receive objects from Speckle Server.
class ReceiveObjects < Action
# rubocop:disable Metrics/ParameterLists
def initialize(stream_id, base, stream_name, branch_name, branch_id, source_app)
def initialize(stream_id, base, stream_name, branch_name, branch_id, source_app, object_id)
super()
@stream_id = stream_id
@base = base
@@ -17,12 +18,15 @@ module SpeckleConnector
@branch_name = branch_name
@branch_id = branch_id
@source_app = source_app
@object_id = object_id
end
# rubocop:enable Metrics/ParameterLists
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def update_state(state)
# content = Operations.receive(@stream_id, @object_id)
converter = Converters::ToNative.new(state, @stream_id, @stream_name, @branch_name, @source_app)
# Have side effects on the sketchup model. It effects directly on the entities by adding new objects.
start_time = Time.now.to_f
@@ -10,7 +10,7 @@ module SpeckleConnector
class ReloadAccounts < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, _data)
def self.update_state(state, _resolve_id, _data)
puts 'Reload of Speckle accounts requested by plugin'
new_speckle_state = state.speckle_state.with_accounts(Accounts.load_accounts)
state = state.with_speckle_state(new_speckle_state)
@@ -10,7 +10,7 @@ module SpeckleConnector
class SelectMappingsFromTable < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, data)
def self.update_state(state, _resolve_id, data)
# Clear first selection
state.sketchup_state.sketchup_model.selection.clear
@@ -0,0 +1,22 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../ui_data/sketchup/selection_info'
module SpeckleConnector
module Actions
# Action to get selection.
class GetSelection < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state)
selected_object_ids = state.sketchup_state.sketchup_model.selection.collect(&:persistent_id)
summary = "Selected #{selected_object_ids.length} objects."
selection_info = UiData::Sketchup::SelectionInfo.new(selected_object_ids, summary)
# js_script = "selectionBinding.receiveResponse('#{resolve_id}', #{selection_info.to_json})"
js_script = "selectionBinding.emit('setSelection', #{selection_info.to_json})"
state.with_add_queue_js_command('setSelection', js_script)
end
end
end
end
@@ -0,0 +1,22 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../sketchup_model/dictionary/send_card_dictionary_handler'
module SpeckleConnector
module Actions
# Action to activate send filter.
class ActivateSendFilter < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id, data, value)
SketchupModel::Dictionary::SendCardDictionaryHandler.update_filter(state.sketchup_state.sketchup_model, data, value)
card_id = "#{data['accountId']}-#{data['projectId']}-#{data['modelId']}"
send_card = state.speckle_state.send_cards[card_id]
puts "Send card filter updated -> #{card_id} -> #{send_card}"
js_script = "sendBindingOld.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('activateSendFilter', js_script)
end
end
end
end
@@ -0,0 +1,22 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../sketchup_model/dictionary/send_card_dictionary_handler'
module SpeckleConnector
module Actions
# Action to activate send filter tag.
class ActivateSendFilterTag < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id, data, value)
SketchupModel::Dictionary::SendCardDictionaryHandler.update_tag_filter(state.sketchup_state.sketchup_model, data, value)
card_id = "#{data['accountId']}-#{data['projectId']}-#{data['modelId']}"
send_card = state.speckle_state.send_cards[card_id]
puts "Send card filter updated -> #{card_id} -> #{send_card}"
js_script = "sendBindingOld.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('activateSendFilterTag', js_script)
end
end
end
end
@@ -0,0 +1,57 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../accounts/accounts'
require_relative '../../convertors/units'
require_relative '../../convertors/to_speckle'
require_relative '../../operations/send'
module SpeckleConnector
module Actions
# Send to server.
class Send < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id, model_card_id)
model_card = state.speckle_state.send_cards[model_card_id]
account = Accounts.get_account_by_id(model_card.account_id)
converter = Converters::ToSpeckle.new(state, @stream_id)
new_speckle_state, base = converter.convert_selection_to_base(state.user_state.preferences)
id, total_children_count, batches, new_speckle_state = converter.serialize(base, new_speckle_state,
state.user_state.preferences)
puts("converted #{base.count} objects for stream #{@stream_id}")
state = state.with_speckle_state(new_speckle_state)
selected_object_ids = state.sketchup_state.sketchup_model.selection.collect(&:persistent_id)
selected_object_ids.each_with_index do |selection_id, i|
sender_progress_args = {
id: model_card_id,
status: selection_id,
progress: i
}
state.instant_message_sender.call("sendBinding.emit('senderProgress', #{sender_progress_args.to_json})")
end
resolve_js_script = "sendBinding.receiveResponse('#{resolve_id}')"
state = state.with_add_queue_js_command('send', resolve_js_script)
args = {
projectId: model_card.project_id,
modelId: model_card.model_id,
token: account['token'],
serverUrl: account['serverInfo']['url'],
accountId: model_card.account_id,
message: model_card.message,
sendObject: {
id: id,
totalChildrenCount: total_children_count,
batches: batches
}
}
js_script = "sendBinding.emit('sendViaBrowser', #{args.to_json})"
state.with_add_queue_js_command('sendViaBrowser', js_script)
end
end
end
end
@@ -0,0 +1,23 @@
# frozen_string_literal: true
require_relative '../action'
require_relative '../../sketchup_model/dictionary/send_card_dictionary_handler'
module SpeckleConnector
module Actions
# Action to check send card expirations.
class SendCardExpirationCheck < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state)
return state unless state.speckle_state.changed_entity_ids.any?
expired_send_cards_ids = state.speckle_state.send_cards.select do |_id, send_card|
send_card.send_filter.check_expiry(state.speckle_state.changed_entity_ids)
end.keys.to_a
js_script = "sendBinding.emit('sendersExpired', #{expired_send_cards_ids.to_json})"
state.with_add_queue_js_command('sendersExpired', js_script)
end
end
end
end
@@ -4,6 +4,7 @@ require_relative 'action'
require_relative 'deactivate_diffing'
require_relative '../convertors/units'
require_relative '../convertors/to_speckle'
require_relative '../operations/send'
module SpeckleConnector
module Actions
@@ -17,11 +18,14 @@ module SpeckleConnector
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def update_state(state)
state = DeactivateDiffing.update_state(state, {})
state = DeactivateDiffing.update_state(state, nil, {})
converter = Converters::ToSpeckle.new(state, @stream_id)
new_speckle_state, base = converter.convert_selection_to_base(state.user_state.preferences)
id, total_children_count, batches, new_speckle_state = converter.serialize(base, new_speckle_state,
state.user_state.preferences)
# TODO: Later active send operation.
# Operations.send(@stream_id, batches)
puts("converted #{base.count} objects for stream #{@stream_id}")
# This is the place we can send information to UI for diffing check
@@ -8,7 +8,7 @@ module SpeckleConnector
class ShowAllEntities < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, _data)
def self.update_state(state, _resolve_id, _data)
# Show all entities first
state.sketchup_state.sketchup_model.entities.each do |ent|
ent.hidden = false
@@ -0,0 +1,46 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Action to get user config.
class GetUserConfig < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id)
# Previously it was stored in user state
# config = state.user_state.preferences.to_json
config = [
{
key: 'darkTheme',
title: 'Theme',
type: 'toggle',
config: {
value: state.user_state.user_preferences[:dark_theme]
}
},
{
key: 'diffing',
title: 'Diffing',
type: 'toggle',
config: {
value: state.user_state.user_preferences[:diffing]
}
},
{
key: 'referencePoint',
title: 'Reference Point',
type: 'dropdown',
config: {
value: 'test',
items: ['test', 'test1', 'test2']
}
}
]
js_script = "connectorConfigBinding.receiveResponse('#{resolve_id}', #{config.to_json})"
state.with_add_queue_js_command('getUserConfig', js_script)
end
end
end
end
@@ -0,0 +1,18 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Action to get user config.
class UpdateUserConfig < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id, new_config)
puts new_config.values
js_script = "connectorConfigBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('updateUserConfig', js_script)
end
end
end
end
@@ -0,0 +1,21 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Test purpose action.
class GetComplexType < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id)
complex_type = {
id: 'complex_type_id',
count: 3
}
js_script = "testBinding.receiveResponse('#{resolve_id}', #{complex_type.to_json})"
state.with_add_queue_js_command('getComplexType', js_script)
end
end
end
end
@@ -0,0 +1,18 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Test purpose action.
class GoAway < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id)
puts 'SketchUp went away :('
js_script = "testBinding.receiveResponse('#{resolve_id}')"
state.with_add_queue_js_command('goAway', js_script)
end
end
end
end
@@ -0,0 +1,21 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Test purpose action.
class SayHi < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id, name, count, say_hello_not_hi)
said_hi = []
count.times do
said_hi.append("#{say_hello_not_hi ? 'Hello' : 'Hi'} #{name}!")
end
js_script = "testBinding.receiveResponse('#{resolve_id}', #{said_hi})"
state.with_add_queue_js_command('sayHi', js_script)
end
end
end
end
@@ -0,0 +1,28 @@
# frozen_string_literal: true
require_relative '../action'
module SpeckleConnector
module Actions
# Test purpose action.
class TriggerEvent < Action
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
# @return [States::State] the new updated state object
def self.update_state(state, resolve_id, event_name)
if event_name == 'emptyTestEvent'
js_script = "testBinding.emit('#{event_name}')"
else
args = {
name: 'Oguzhan',
isOk: true,
count: 3
}
js_script = "testBinding.emit('#{event_name}', #{args.to_json})"
end
resolve_js_script = "testBinding.receiveResponse('#{resolve_id}')"
state = state.with_add_queue_js_command('triggerEventResolve', resolve_js_script)
state.with_add_queue_js_command('triggerEvent', js_script)
end
end
end
end
@@ -21,17 +21,20 @@ module SpeckleConnector
def initialize(menu_commands, state, ui_controller)
@menu_commands = menu_commands
@state = state
@ui_controller = ui_controller
end
def instant_message_sender(message)
ui_controller.user_interfaces.each_value do |dialog|
dialog.execute_script(message)
end
end
def speckle_loaded?
state.speckle_state?
end
def update_ui!
ui_controller.update_ui(state)
end
# Attach observers to application when speckle initialized via menu commands.
def add_observer_handler!(observer_handler)
@observer_handler = observer_handler
@@ -40,7 +43,12 @@ module SpeckleConnector
# Send messages to HtmlDialog if any.
def send_messages!
queue = @state.speckle_state.message_queue
queue.each_value { |value| ui_controller.user_interfaces[Ui::SPECKLE_UI_ID].dialog.execute_script(value) }
queue.each_value do |value|
# FIXME: here need to identify message scope
ui_controller.user_interfaces.each_value do |dialog|
dialog.execute_script(value)
end
end
update_state!(Actions::ClearQueue)
end
@@ -50,7 +58,6 @@ module SpeckleConnector
old_state = @state
@state = action.update_state(old_state, *parameters)
send_messages! if @state.speckle_state.message_queue.any?
update_ui! unless @state.equal?(old_state)
end
end
end
+39
View File
@@ -0,0 +1,39 @@
# frozen_string_literal: true
require_relative '../speckle_objects/other/color'
module SpeckleConnector
module Cards
# Card for sketchup connector to communicate speckle.
class Card < Hash
# @return [String] id of the card.
attr_reader :id
# @return [String] account id of the card.
attr_reader :account_id
# @return [String] project id of the card.
attr_reader :project_id
# @return [String] model id of the card.
attr_reader :model_id
# @return [Boolean] card is valid or not.
attr_reader :valid
def initialize(card_id, account_id, project_id, model_id)
super()
@id = card_id
@account_id = account_id
@project_id = project_id
@model_id = model_id
@valid = true
self[:id] = card_id
self[:account_id] = account_id
self[:project_id] = project_id
self[:model_id] = model_id
self[:valid] = @valid
end
end
end
end
+31
View File
@@ -0,0 +1,31 @@
# frozen_string_literal: true
require_relative 'card'
module SpeckleConnector
module Cards
# Send card for sketchup connector to communicate speckle.
class SendCard < Card
# @return [Filters::Send::EverythingFilter | Filters::Send::SelectionFilter | Filters::Send::LayerFilter] filter of the card.
attr_reader :send_filter
# @return [Object] send settings of the card.
attr_reader :send_settings
attr_reader :type_discriminator
# @return [String, NilClass] message to send
attr_reader :message
def initialize(card_id, account_id, project_id, model_id, send_filter, send_settings)
super(card_id, account_id, project_id, model_id)
@send_filter = send_filter
@send_settings = send_settings
@type_discriminator = 'SenderModelCard'
self[:sendFilter] = send_filter
self[:sendSettings] = send_settings
end
end
end
end
@@ -0,0 +1,19 @@
# frozen_string_literal: true
require_relative 'card'
module SpeckleConnector
module Cards
# Send card for sketchup connector to communicate speckle.
class SendCardMultipleFilters < Card
# @return [Hash{String=>Filter}] filters of the card.
attr_reader :filters
def initialize(card_id, account_id, project_id, model_id, filters)
super(card_id, account_id, project_id, model_id)
@filters = filters
self[:filters] = filters
end
end
end
end
@@ -7,10 +7,10 @@ module SpeckleConnector
# Command to update state of the application.
class ActionCommand < Command
# @param app [App::SpeckleConnectorApp] the app object to run command on
# @param binding [Ui::Binding] binding object holds commands to call
# @param action [#update_state] the action that knows how to change the state of the speckle app
def initialize(app, action)
super(app)
@app = app
def initialize(app, binding, action)
super(app, binding)
@action = action
end
@@ -7,7 +7,7 @@ module SpeckleConnector
module Commands
# Command to activate diffing for stream.
class ActivateDiffing < Command
def _run(data)
def _run(_resolve_id, data)
stream_id = data['stream_id']
action = Actions::ActivateDiffing.new(stream_id)
app.update_state!(action)
@@ -7,7 +7,7 @@ module SpeckleConnector
module Commands
# Command to apply mapping for selected entities.
class ApplyMappings < Command
def _run(data)
def _run(_resolve_id, data)
entities_to_map = data['entitiesToMap']
method = data['method']
category = data['category']
@@ -7,7 +7,7 @@ module SpeckleConnector
module Commands
# Command to clear mapping for selected entities.
class ClearMappings < Command
def _run(data)
def _run(_resolve_id, data)
entities_to_map = data['entitiesToClearMap']
is_definition = data['isDefinition']
action = Actions::ClearMappings.new(entities_to_map, is_definition)
+16 -8
View File
@@ -1,5 +1,7 @@
# frozen_string_literal: true
require_relative '../actions/handle_error'
module SpeckleConnector
module Commands
# Base command schema to wrap common operations for all commands.
@@ -7,19 +9,25 @@ module SpeckleConnector
# @return [App::SpeckleConnectorApp] the main app object
attr_reader :app
# @return [Ui::View] view object holds dialog and it's state
attr_reader :view
# @return [Ui::Binding] binding object holds dialog and it's state
attr_reader :binding
# @@param app [App::SpeckleConnectorApp] the main app object
def initialize(app)
# @param app [App::SpeckleConnectorApp] the main app object
# @param binding [Ui::Binding] binding object holds commands to call
def initialize(app, binding)
@app = app
@view = app.ui_controller.user_interfaces[Ui::SPECKLE_UI_ID]
@binding = binding
end
def run(*parameters)
# Run here common operations that same for each command.
with_observers_disabled do
_run(*parameters)
begin
# Run here common operations that same for each command.
with_observers_disabled do
_run(*parameters)
end
rescue StandardError => e
action = Actions::HandleError.new(e, @binding.name, @action, parameters)
app.update_state!(action)
end
end
@@ -1,15 +0,0 @@
# frozen_string_literal: true
require_relative 'command'
module SpeckleConnector
module Commands
# Run this command when the UI is ready to get data
class DialogReady < Command
# Update the selected user interface
def _run(_data)
view.update_view(app.state)
end
end
end
end
@@ -0,0 +1,87 @@
# frozen_string_literal: true
require_relative 'command'
require_relative '../ui/dui3_dialog'
require_relative '../states/initial_state'
require_relative '../ui/legacy_binding'
require_relative '../ui/bindings/accounts_binding'
require_relative '../ui/bindings/base_binding'
require_relative '../ui/bindings/send_binding'
require_relative '../ui/bindings/selection_binding'
require_relative '../ui/test_binding'
require_relative '../ui/receive_binding'
require_relative '../ui/bindings/config_binding'
require_relative '../ui/sketchup_config_binding'
require_relative '../actions/initialize_speckle'
require_relative '../observers/factory'
module SpeckleConnector
module Commands
# Command to initialize Speckle UI and register it to ui_controller.
# This is the command where we show UI to user.
class InitializeDUI3Speckle < Command
SPECKLE_DUI3 = 'speckle_dui3'
def dialog_title
"Speckle #{CONNECTOR_VERSION}"
end
private
def _run
app = self.app
if !app.state.instance_of?(States::InitialState) && app.ui_controller.user_interfaces[SPECKLE_DUI3]
dialog = app.ui_controller.user_interfaces[SPECKLE_DUI3]
dialog.show
return
end
initialize_speckle_dui3(app)
end
# Do the actual Speckle initialization.
# rubocop:disable Naming/VariableNumber
def initialize_speckle_dui3(app)
# TODO: Initialize here speckle states and observers.
observer_handler = Observers::Factory.create_handler(app)
app.add_observer_handler!(observer_handler)
observers = Observers::Factory.create_observers(observer_handler)
app.update_state!(Actions::InitializeSpeckle, observers, app.method(:instant_message_sender))
dialog_specs = {
dialog_id: SPECKLE_DUI3,
dialog_title: dialog_title,
height: 950,
width: 300
}
# Init bindings
base_binding = Ui::BaseBinding.new(app, Ui::BASE_BINDING_NAME)
accounts_binding = Ui::AccountsBinding.new(app, Ui::ACCOUNTS_BINDING_NAME)
send_binding = Ui::SendBinding.new(app, Ui::SEND_BINDING_NAME)
selection_binding = Ui::SelectionBinding.new(app, Ui::SELECTION_BINDING_NAME)
test_bindings = Ui::TestBinding.new(app, Ui::TEST_BINDINGS_NAME)
receive_bindings = Ui::ReceiveBinding.new(app, Ui::RECEIVE_BINDING_NAME)
config_bindings = Ui::ConfigBinding.new(app, Ui::CONFIG_BINDING_NAME)
# send_bindings = Ui::SendBinding.new(app, Ui::SEND_BINDING_NAME)
connector_config_bindings = Ui::SketchupConfigBinding.new(app, Ui::CONNECTOR_CONFIG_BINDING_NAME)
# Init dialog
dui3_dialog = SpeckleConnector::Ui::DUI3Dialog.new(**dialog_specs)
# Register bindings to dialog
dui3_dialog.bindings[Ui::BASE_BINDING_NAME] = base_binding
dui3_dialog.bindings[Ui::ACCOUNTS_BINDING_NAME] = accounts_binding
dui3_dialog.bindings[Ui::SEND_BINDING_NAME] = send_binding
dui3_dialog.bindings[Ui::TEST_BINDINGS_NAME] = test_bindings
dui3_dialog.bindings[Ui::RECEIVE_BINDING_NAME] = receive_bindings
dui3_dialog.bindings[Ui::CONFIG_BINDING_NAME] = config_bindings
dui3_dialog.bindings[Ui::CONNECTOR_CONFIG_BINDING_NAME] = connector_config_bindings
# dui3_dialog.bindings[Ui::SEND_BINDING_NAME] = send_bindings
dui3_dialog.bindings[Ui::SELECTION_BINDING_NAME] = selection_binding
app.ui_controller.register_ui(SPECKLE_DUI3, dui3_dialog)
dui3_dialog.show
end
# rubocop:enable Naming/VariableNumber
end
end
end
@@ -2,15 +2,17 @@
require_relative 'command'
require_relative '../states/initial_state'
require_relative '../ui/vue_view'
require_relative '../ui/legacy_binding'
require_relative '../actions/initialize_speckle'
require_relative '../observers/factory'
module SpeckleConnector
module Commands
# Command to initialize Speckle UI and register it to ui_controller.
# Command to initialize old Speckle UI and register it to ui_controller.
# This is the command where we show UI to user.
class InitializeSpeckle < Command
SPECKLE_LEGACY_UI = 'speckle_legacy_ui'
def dialog_title
"Speckle #{CONNECTOR_VERSION}"
end
@@ -19,32 +21,34 @@ module SpeckleConnector
def _run
app = self.app
unless app.state.instance_of?(States::InitialState)
vue_view = app.ui_controller.user_interfaces[Ui::SPECKLE_UI_ID]
if !app.state.instance_of?(States::InitialState) && app.ui_controller.user_interfaces[SPECKLE_LEGACY_UI]
vue_view = app.ui_controller.user_interfaces[SPECKLE_LEGACY_UI]
vue_view.show
return
end
initialize_speckle(app)
initialize_speckle_legacy_view(app)
end
# Do the actual Speckle initialization.
def initialize_speckle(app)
def initialize_speckle_legacy_view(app)
# TODO: Initialize here speckle states and observers.
observer_handler = Observers::Factory.create_handler(app)
app.add_observer_handler!(observer_handler)
observers = Observers::Factory.create_observers(observer_handler)
app.update_state!(Actions::InitializeSpeckle, observers)
dialog_specs = {
dialog_id: Ui::SPECKLE_UI_ID,
dialog_id: SPECKLE_LEGACY_UI,
htm_file: Ui::VUE_UI_HTML,
dialog_title: dialog_title,
height: 950,
width: 300
}
vue_view = Ui::VueView.new(dialog_specs, app)
app.ui_controller.register_ui(Ui::SPECKLE_UI_ID, vue_view)
vue_view.show
legacy_ui_dialog = SpeckleConnector::Ui::Dialog.new(**dialog_specs)
legacy_binding = Ui::LegacyBinding.new(app, 'legacy_ui')
legacy_ui_dialog.bindings[Ui::SPECKLE_LEGACY_BINDING_NAME] = legacy_binding
app.ui_controller.register_ui(SPECKLE_LEGACY_UI, legacy_ui_dialog)
legacy_ui_dialog.show
end
end
end
@@ -7,7 +7,7 @@ module SpeckleConnector
module Commands
# Command to update mapper source.
class MapperSourceUpdated < Command
def _run(data)
def _run(_resolve_id, data)
base = data['base']
stream_id = data['stream_id']
commit_id = data['commit_id']
@@ -8,7 +8,7 @@ module SpeckleConnector
module Commands
# Command to update theme.
class ModelPreferencesUpdated < Command
def _run(data)
def _run(_resolve_id, data)
preference = data['preference']
new_value = data['value']
app.update_state!(Actions::ModelPreferencesUpdated.new(preference, new_value))
@@ -8,7 +8,7 @@ module SpeckleConnector
module Commands
# Command to notify connected.
class NotifyConnected < Command
def _run(data)
def _run(_resolve_id, data)
stream_id = data['stream_id']
app.update_state!(Actions::Connected)
app.update_state!(Actions::SendFromQueue.new(stream_id))
@@ -7,14 +7,15 @@ module SpeckleConnector
module Commands
# Command to receive objects from Speckle Server.
class ReceiveObjects < Command
def _run(data)
def _run(_resolve_id, data)
stream_id = data['stream_id']
base = data['base']
branch_name = data['branch_name']
branch_id = data['branch_id']
stream_name = data['stream_name']
source_app = data['source_app']
action = Actions::ReceiveObjects.new(stream_id, base, stream_name, branch_name, branch_id, source_app)
object_id = data['object_id']
action = Actions::ReceiveObjects.new(stream_id, base, stream_name, branch_name, branch_id, source_app, object_id)
app.update_state!(action)
end
end
@@ -8,7 +8,7 @@ module SpeckleConnector
module Commands
# Command to remove stream.
class RemoveStream < Command
def _run(data)
def _run(_resolve_id, data)
stream_id = data['stream_id']
action = Actions::RemoveStream.new(stream_id)
app.update_state!(action)
@@ -9,7 +9,7 @@ module SpeckleConnector
module Commands
# Command to saved stream.
class SaveStream < Command
def _run(data)
def _run(_resolve_id, data)
stream_id = data['stream_id']
app.update_state!(Actions::SaveStream.new(stream_id))
end
@@ -7,7 +7,7 @@ module SpeckleConnector
module Commands
# Command to send selection to Speckle Server.
class SendSelection < Command
def _run(data)
def _run(_resolve_id, data)
stream_id = data['stream_id']
action = Actions::SendSelection.new(stream_id)
app.update_state!(action)
@@ -3,6 +3,7 @@
require_relative 'menu_command_handler'
require_relative 'action_command'
require_relative 'initialize_speckle'
require_relative 'initialize_dui3_speckle'
require_relative '../actions/one_click_send'
module SpeckleConnector
@@ -10,6 +11,7 @@ module SpeckleConnector
# Speckle menu commands that adds them to Sketchup menu and toolbar.
class SpeckleMenuCommands
CMD_INITIALIZE_SPECKLE = :initialize_speckle
CMD_INITIALIZE_DUI3_SPECKLE = :initialize_dui3_speckle
CMD_SEND_TO_SPECKLE = :send_to_speckle
CMD_RECEIVE_FROM_SPECKLE = :receive_from_speckle
@@ -26,6 +28,10 @@ module SpeckleConnector
commands.add_to_menu!(CMD_INITIALIZE_SPECKLE, speckle_menu)
commands.add_to_toolbar!(CMD_INITIALIZE_SPECKLE, speckle_toolbar)
commands[CMD_INITIALIZE_DUI3_SPECKLE] = initialize_dui3_speckle_command(app)
commands.add_to_menu!(CMD_INITIALIZE_DUI3_SPECKLE, speckle_menu)
commands.add_to_toolbar!(CMD_INITIALIZE_DUI3_SPECKLE, speckle_toolbar)
# commands[CMD_SEND_TO_SPECKLE] = send_command(app)
# commands.add_to_menu!(CMD_SEND_TO_SPECKLE, speckle_menu)
# commands.add_to_toolbar!(CMD_SEND_TO_SPECKLE, speckle_toolbar)
@@ -33,7 +39,7 @@ module SpeckleConnector
def self.initialize_speckle_command(app)
cmd = MenuCommandHandler.sketchup_command(
InitializeSpeckle.new(app), 'Initialize Speckle'
InitializeSpeckle.new(app, nil), 'Initialize Speckle'
)
cmd.tooltip = 'Launch Connector'
cmd.status_bar_text = 'Opens the Speckle Connector window'
@@ -42,9 +48,20 @@ module SpeckleConnector
cmd
end
def self.initialize_dui3_speckle_command(app)
cmd = MenuCommandHandler.sketchup_command(
InitializeDUI3Speckle.new(app, nil), 'Initialize DUI3 Speckle'
)
cmd.tooltip = 'Launch Connector with DUI3'
cmd.status_bar_text = 'Opens the Speckle Connector DUI3 Window'
cmd.small_icon = '../../img/s2logo_dui3.png'
cmd.large_icon = '../../img/s2logo_dui3.png'
cmd
end
def self.send_command(app)
cmd = MenuCommandHandler.sketchup_command(
ActionCommand.new(app, Actions::OneClickSend), 'Send to Speckle'
ActionCommand.new(app, nil, Actions::OneClickSend), 'Send to Speckle'
)
cmd.tooltip = 'Send to Speckle'
cmd.status_bar_text = 'Send to Speckle'
@@ -8,7 +8,7 @@ module SpeckleConnector
module Commands
# Command to update preferences.
class UserPreferencesUpdated < Command
def _run(data)
def _run(_resolve_id, data)
preference_hash = data['preference_hash']
preference = data['preference']
new_value = data['value']
@@ -5,6 +5,8 @@ module SpeckleConnector
SPECKLE_MAPPING_TOOL_SCHEMA = 'Speckle_Mapping_Tool_Schema'
SPECKLE_SCHEMA = 'Speckle_Schema'
SPECKLE_SEND_CARDS = 'Speckle_Send_Cards'
SPECKLE_ID = 'speckle_id'
SPECKLE_TYPE = 'speckle_type'
APPLICATION_ID = 'application_id'
@@ -310,8 +310,12 @@ module SpeckleConnector
Digest::MD5.hexdigest(traversed_base.to_json)
end
def batch_objects
@objects
end
# rubocop:disable Metrics/MethodLength
def batch_objects(max_batch_size_mb = 1)
def batch_json_objects(max_batch_size_mb = 1)
max_size = 1000 * 1000 * max_batch_size_mb
batches = []
batch = '['
@@ -44,7 +44,7 @@ module SpeckleConnector
serializer = SpeckleConnector::Converters::BaseObjectSerializer.new(speckle_state, stream_id, preferences)
t = Time.now.to_f
id = serializer.serialize(base_and_entity)
batches = serializer.batch_objects
batches = serializer.batch_json_objects
# write_to_speckle_folder(id, batches)
puts "Generating traversed object elapsed #{Time.now.to_f - t} s"
base_total_children_count = serializer.total_children_count(id)
+23
View File
@@ -0,0 +1,23 @@
# frozen_string_literal: true
module SpeckleConnector
module Filters
# Base filters for sketchup connector.
class Filter < Hash
# @return [String] id of the filter
attr_reader :id
# @return [String] name of the filter
attr_reader :name
def initialize(id, name)
super()
@id = id
@name = name
self[:id] = id
self[:name] = name
end
end
end
end
@@ -0,0 +1,20 @@
# frozen_string_literal: true
require_relative 'filter'
module SpeckleConnector
module Filters
# Search filters for sketchup connector.
# TODO: LATER!
class SearchFilter < Filter
# @return [Array<Tag>] id of the filter
attr_reader :tags
def initialize(id, name, input, duplicable, tags, active_tags)
super(id, name, input, duplicable)
@tags = tags
@active_tags = active_tags
end
end
end
end
@@ -0,0 +1,25 @@
# frozen_string_literal: true
require_relative '../../ui_data/components/selections/list_selection_item'
module SpeckleConnector
module Filters
module Send
# Everything filter for sketchup connector to send all.
class EverythingFilter < UiData::Components::Selections::ListSelectionItem
def initialize
super('everything', 'Everything', nil,
'All supported objects in the currently opened file.')
end
def self.from_json(_data)
EverythingFilter.new
end
def check_expiry(_ids)
true
end
end
end
end
end
@@ -0,0 +1,28 @@
# frozen_string_literal: true
require_relative '../../ui_data/components/selections/list_selection'
module SpeckleConnector
module Filters
module Send
# Layer (tag) filter for sketchup connector to send all.
class LayerFilter < UiData::Components::Selections::ListSelection
def initialize(items, selected_items)
super('tags', 'Tags', items, selected_items, true)
end
def self.from_json(data)
items = data['items'].collect do |key, item|
[key, [UiData::Components::Selections::ListSelectionItem.new(item['id'], item['name'], item['color'], '')]]
end.to_h
LayerFilter.new(items, data['selectedItems'])
end
def check_expiry(_ids)
# TODO: Implement!
false
end
end
end
end
end
@@ -0,0 +1,40 @@
# frozen_string_literal: true
require_relative '../../ui_data/components/selections/list_selection_item'
module SpeckleConnector
module Filters
module Send
# Selection filter for sketchup connector to send all.
class SelectionFilter < UiData::Components::Selections::ListSelectionItem
DEFAULT_SUMMARY = 'User based selection filter. UI should replace this summary with the selection info summary!'
# @return [Array<Integer>]
attr_reader :selected_object_ids
def initialize(selected_object_ids, summary = DEFAULT_SUMMARY)
super('selection', 'Selection', nil, summary)
@selected_object_ids = selected_object_ids
self[:selectedObjectIds] = selected_object_ids
end
def check_expiry(ids)
selected_object_ids.intersection(ids.to_a).any?
end
def self.from_json(_data)
SelectionFilter.new([])
end
def self.read_from_document(data)
SelectionFilter.new(data['selectedObjectIds'], data['summary'])
end
def self.from_ui_data(data)
# FIXME: Solve inconsistency! UI send data as hash which should be array
SelectionFilter.new(data['selectedObjectIds'].values, data['summary'])
end
end
end
end
end
@@ -0,0 +1,54 @@
# frozen_string_literal: true
require_relative '../filters/send/selection_filter'
require_relative '../filters/send/everything_filter'
require_relative '../filters/send/layer_filter'
require_relative '../ui_data/components/selections/list_selection'
require_relative '../ui_data/components/selections/list_selection_item'
require_relative '../speckle_objects/other/color'
module SpeckleConnector
module Filters
# Send filters for sketchup connector.
class SendFilters
TYPE_CLASSES = {
'everything': Filters::Send::EverythingFilter,
'selection': Filters::Send::SelectionFilter,
'tags': Filters::Send::LayerFilter
}.freeze
def self.get_filter_from_ui_data(filter)
method = TYPE_CLASSES[filter['name'].downcase.to_sym].method(:from_ui_data)
method.call(filter)
end
def self.get_filter_from_document(filter)
method = TYPE_CLASSES[filter['name'].downcase.to_sym].method(:read_from_document)
method.call(filter)
end
# Get default send filters.
# @param sketchup_model [Sketchup::Model] active model.
def self.get_default(sketchup_model)
everything = Filters::Send::EverythingFilter.new
selection = Filters::Send::SelectionFilter.new([])
layer_items = sketchup_model.layers.collect do |layer|
UiData::Components::Selections::ListSelectionItem.new(
layer.persistent_id, layer.display_name, SpeckleObjects::Other::Color.to_rgb(layer.color), ''
)
end
tags = Filters::Send::LayerFilter.new(layer_items, layer_items.collect(&:name))
[everything, selection, tags]
end
def self.get_filters_from_model(filters)
filters_objects = filters['items'].collect do |filter_key, filter|
from_json = TYPE_CLASSES[filter_key.to_sym].method(:from_json)
[filter_key, from_json.call(filter)]
end.to_h
UiData::Components::Selections::ListSelection.new(filters['id'], filters['name'],
filters_objects, filters['selectedItems'], filters['multipleSelection'])
end
end
end
end
+22
View File
@@ -0,0 +1,22 @@
# frozen_string_literal: true
module SpeckleConnector
module Filters
# Tag definition for filters for sketchup connector.
class Tag < Hash
attr_reader :id
attr_reader :name
attr_reader :color
def initialize(id, name, color)
super()
@id = id
@name = name
@color = color
self[:id] = id
self[:name] = name
self[:color] = color
end
end
end
end
@@ -0,0 +1,25 @@
# frozen_string_literal: true
require_relative 'tag'
require_relative 'filter'
module SpeckleConnector
module Filters
# Tag filters for sketchup connector.
class TagFilter < Filter
# @return [Array<Tag>] id of the filter
attr_reader :tags
# @return [Array<String>] id of the filter
attr_reader :active_tags
def initialize(id, name, input, duplicable, tags, active_tags)
super(id, name, input, duplicable)
@tags = tags
@active_tags = active_tags
self[:tags] = tags
self[:activeTags] = active_tags
end
end
end
end
@@ -19,7 +19,7 @@ module SpeckleConnector
# @return [Array<SpeckleObjects::BuiltElements::Level>] levels in the source branch.
attr_reader :levels
# @return [ImmutableHash{String=>Array<SpeckleObjects::BuiltElements::Revit::RevitElementType>}] revit element
# @return [Immutable::Hash{String=>Array<SpeckleObjects::BuiltElements::Revit::RevitElementType>}] revit element
# types.
attr_reader :types
@@ -0,0 +1,31 @@
# frozen_string_literal: true
require_relative '../accounts/accounts'
module SpeckleConnector
# Operations between server and connector.
module Operations
# Receive operation. (WIP)
def self.receive(stream_id, object_id)
default_account = Accounts.default_account
url = default_account['serverInfo']['url']
token = default_account['token']
uri = URI.parse("#{url}/objects/#{stream_id}/#{object_id}/single")
headers = {}
headers['Authorization'] = "Bearer #{token}"
headers['Accept'] = 'text/plain'
content = nil
@request = Sketchup::Http::Request.new(uri.to_s, Sketchup::Http::GET)
@request.headers = headers
# Can't catch here content as sync...!
@request.start do |req, res|
content = res.body
end
content
end
end
end
+50
View File
@@ -0,0 +1,50 @@
# frozen_string_literal: true
require_relative '../accounts/accounts'
module SpeckleConnector
# Operations between server and connector.
module Operations
# Formats payload as multipart data.
# @param boundary [String] randomly generated boundary to wrap data.
# @param payload_data [String] data to wrap between boundaries
# @param content_type [String] type of the data i.e. application/json, application/gzip...
# @return [String] formatted data for multipart form-data.
def self.format_payload(boundary, payload_data, content_type)
data = []
data << "--#{boundary}\r\n"
data << "Content-Disposition: form-data; name=\"file\"; filename=\"data\"\r\n"
data << "Content-Type: #{content_type}\r\n\r\n"
data << payload_data
data << "\r\n\r\n--#{boundary}--\r\n"
data.join
end
# Send operation. (WIP)
# @param stream_id [String] stream id to send batches.
# @param batches [Array<String>] batches to send stream.
def self.send_json(stream_id, batches)
account = Accounts.default_account
boundary = "----RubyMultipartClient#{rand(1000000)}ZZZZZ"
payload = format_payload(boundary, batches, 'application/json')
uri = URI.parse("#{account['serverInfo']['url']}/objects/#{stream_id}")
headers = {}
headers['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
headers['Authorization'] = "Bearer #{account['token']}"
request = Sketchup::Http::Request.new(uri.to_s, Sketchup::Http::POST)
request.headers = headers
request.body = payload
request.start do |req, res|
# Not entering
p res
p res.status_code
puts res.body
end
end
end
end
@@ -59,6 +59,19 @@ module SpeckleConnector
entity.attribute_dictionaries.delete(dictionary_name)
end
# @param dict [Sketchup::AttributeDictionary] attribute dictionary to get complete hash.
def self.dict_to_h(dict)
hash = {}
hash.merge!(dict.to_h)
unless dict.attribute_dictionaries.nil?
dict.attribute_dictionaries.each do |sub_dict|
sub_hash = dict_to_h(sub_dict)
hash[sub_dict.name] = sub_hash
end
end
hash
end
# @return [String] the name of the dictionary to read from
def self.dictionary_name
raise NotImplementedError 'Implement this in subclass'
@@ -0,0 +1,114 @@
# frozen_string_literal: true
require 'delegate'
require_relative 'dictionary_handler'
require_relative '../../constants/dict_constants'
module SpeckleConnector
module SketchupModel
module Dictionary
# Read and write attributes for Speckle send cards on SketchUp model.
class SendCardDictionaryHandler < DictionaryHandler
# @param send_card [Cards::SendCard] card to save model
# @param sketchup_model [Sketchup::Model] sketchup model to save cards into it's attribute dictionary
def self.save_card_to_model(send_card, sketchup_model)
send_cards_dict = send_cards_dict(sketchup_model)
serialize_obj_to_dict(send_card.id, send_card, send_cards_dict)
end
# @param obj [Object] object to write
# @param dict [Sketchup::AttributeDictionary] attribute dictionary to write data.
def self.serialize_obj_to_dict(dict_name, obj, dict)
dict_to_write = dict.attribute_dictionary(dict_name, true)
obj.each do |key, value|
# value = obj.instance_variable_get(var)
# var_name = var.to_s[1..-1]
if value.is_a?(Hash)
serialize_obj_to_dict(key.to_s, value, dict_to_write)
else
dict_to_write[key] = value
end
end
end
def self.get_card_dict(sketchup_model, data)
send_cards_dict = send_cards_dict(sketchup_model)
send_cards_dict.attribute_dictionaries.find { |dict| dict.name == data['id'] }
end
def self.get_card_filters_dict(sketchup_model, data)
card_dict = get_card_dict(sketchup_model, data)
card_dict.attribute_dictionaries.find { |dict| dict.name == 'filters' }
end
def self.get_card_filter_item_dict(sketchup_model, data)
filters_dict = get_card_filters_dict(sketchup_model, data)
items_dict = filters_dict.attribute_dictionaries.find { |dict| dict.name == 'items' }
items_dict.attribute_dictionaries.find { |dict| dict.name == data['filterId'] }
end
def self.update_filter(sketchup_model, data, value)
filter_dict = get_card_filters_dict(sketchup_model, data)
if filter_dict['multipleSelection']
filter_dict['selectedItems'] = if value
filter_dict['selectedItems'] + [data['filterId']]
else
filter_dict['selectedItems'] - [data['filterId']]
end
else
filter_dict['selectedItems'] = [data['filterId']]
end
end
def self.update_tag_filter(sketchup_model, data, value)
filter_dict = get_card_filter_item_dict(sketchup_model, data)
if filter_dict['multipleSelection']
filter_dict['selectedItems'] = if value
filter_dict['selectedItems'] + [data['tagId']]
else
filter_dict['selectedItems'] - [data['tagId']]
end
else
filter_dict['selectedItems'] = [data['tagId']]
end
end
def self.serialize_obj_to_dict_old(dict_name, obj, dict)
obj.instance_variables.each do |var|
dict_to_write = dict
value = obj.instance_variable_get(var)
var_name = var.to_s[1..-1]
if value.is_a?(Hash)
dict_to_write = dict_to_write.attribute_dictionary(dict_name, true)
dict_to_write = dict_to_write.attribute_dictionary(var_name, true)
value.each do |key, hash_value|
serialize_obj_to_dict(key.to_s, hash_value, dict_to_write)
end
else
dict_to_write.set_attribute(dict_name, var_name, value)
end
end
end
def self.send_cards_dict(sketchup_model)
speckle_dict = sketchup_model.attribute_dictionary('Speckle', true)
speckle_dict.attribute_dictionary(SPECKLE_SEND_CARDS, true)
end
def self.get_cards_from_dict(sketchup_model)
send_cards_dict = send_cards_dict(sketchup_model)
return [] if send_cards_dict.attribute_dictionaries.nil?
dict_to_h(send_cards_dict)
end
# @return [String] the name of the dictionary to read from
def self.dictionary_name
SPECKLE_SEND_CARDS
end
end
end
end
end
@@ -110,7 +110,8 @@ module SpeckleConnector
entities, &convert_to_native)
# Find and assign material if exist
unless mesh['renderMaterial'].nil?
material_name = mesh['renderMaterial']['name'] || mesh['renderMaterial']['id']
material_name = mesh['renderMaterial']['name'] || mesh['renderMaterial']['id'] ||
mesh['renderMaterial']['diffuse'].to_s
# Retrieve material from state
material = state.sketchup_state.materials.by_id(material_name)
end
@@ -29,6 +29,18 @@ module SpeckleConnector
[rgba[3] << 24 | rgba[0] << 16 | rgba[1] << 8 | rgba[2]].pack('l').unpack1('l').to_i
end
# @param color [Sketchup::Color] color to convert speckle object
def self.to_hex(color)
r, g, b, a = color.to_a
"#%02X%02X%02X" % [r, g, b] # Scale alpha value to 0-255 range
end
# @param color [Sketchup::Color] color to convert speckle object
def self.to_rgb(color)
r, g, b, a = color.to_a
"#{r},#{g},#{b}"
end
# @param argb [Numeric] int value of the corresponding color
# @return [Sketchup::Color] sketchup color
def self.from_int(argb)
@@ -57,7 +57,7 @@ module SpeckleConnector
materials = state.sketchup_state.materials
# return material with same name if it exists
name = render_material['name'] || render_material['id']
name = render_material['name'] || render_material['id'] || render_material['diffuse'].to_s
material = materials.by_id(name)
return state, [material] if material
@@ -11,7 +11,7 @@ module SpeckleConnector
class SpeckleMapperState
include Immutable::ImmutableUtils
# @return [ImmutableHash{Integer=>Sketchup::Entity}] persistent_id of the sketchup entity and itself
# @return [Immutable::Hash{Integer=>Sketchup::Entity}] persistent_id of the sketchup entity and itself
attr_reader :mapped_entities
# @return [Mapper::MapperSource] source of the mapper.
+30 -3
View File
@@ -11,10 +11,16 @@ module SpeckleConnector
class SpeckleState
include Immutable::ImmutableUtils
# @return [Immutable::Hash{String=>Cards::SendCard}] send cards.
attr_reader :send_cards
# @return [Immutable::Set] changed entity ids.
attr_reader :changed_entity_ids
# @return [States::SpeckleMapperState] state of the mapper.
attr_reader :speckle_mapper_state
# @return [ImmutableHash{Integer=>SpeckleEntities::SpeckleEntity}] persistent_id of the sketchup entity and
# @return [Immutable::Hash{Integer=>SpeckleEntities::SpeckleEntity}] persistent_id of the sketchup entity and
# corresponding speckle entity
attr_reader :speckle_entities
@@ -35,11 +41,11 @@ module SpeckleConnector
attr_accessor :relation
# TODO: Do cashing later
# @return [ImmutableHash{String=>SpeckleObjects::Other::RenderMaterial}] converted render materials
# @return [Immutable::Hash{String=>SpeckleObjects::Other::RenderMaterial}] converted render materials
attr_accessor :render_materials
# TODO: Do cashing later
# @return [ImmutableHash{String=>SpeckleObjects::Other::BlockDefinition}] converted component definitions
# @return [Immutable::Hash{String=>SpeckleObjects::Other::BlockDefinition}] converted component definitions
attr_accessor :definitions
def initialize(accounts, observers, queue, stream_queue)
@@ -47,9 +53,11 @@ module SpeckleConnector
@observers = observers
@message_queue = queue
@stream_queue = stream_queue
@changed_entity_ids = Immutable::EmptySet
@speckle_entities = Immutable::EmptyHash
@render_materials = Immutable::EmptyHash
@definitions = Immutable::EmptyHash
@send_cards = Immutable::EmptyHash
@relation = Relations::ManyToOneRelation.new
@speckle_mapper_state = SpeckleMapperState.new
end
@@ -63,6 +71,11 @@ module SpeckleConnector
with(:@message_queue => new_queue)
end
def with_add_queue_js_command(callback_name, js_command)
new_queue = message_queue.merge("#{callback_name}": js_command)
with(:@message_queue => new_queue)
end
def with_mapped_entities_queue(mapped_entities)
new_queue = message_queue.merge({ "mappedEntitiesUpdated":
"mappedEntitiesUpdated(#{JSON.generate(mapped_entities)})" })
@@ -130,6 +143,20 @@ module SpeckleConnector
with(:@speckle_entities => new_speckle_entities)
end
def with_send_card(send_card)
new_send_cards = send_cards.put(send_card.id, send_card)
with(:@send_cards => new_send_cards)
end
def with_empty_changed_object_ids
with(:@changed_entity_ids => Immutable::EmptySet)
end
def with_changed_object_ids(ids)
new_ids = changed_entity_ids + Immutable::Set.new(ids)
with(:@changed_entity_ids => new_ids)
end
def with_relation(new_relation)
with(:@relation => new_relation)
end
+10 -1
View File
@@ -17,10 +17,14 @@ module SpeckleConnector
# @return [States::UserState] the user specific part of the states
attr_reader :user_state
def initialize(user_state, speckle_state, sketchup_state, is_connected)
# @return [Proc] call to send message immediately to ui.
attr_reader :instant_message_sender
def initialize(user_state, speckle_state, sketchup_state, is_connected, &instant_message_sender)
@speckle_state = speckle_state
@is_connected = is_connected
@sketchup_state = sketchup_state
@instant_message_sender = instant_message_sender
super(user_state)
end
@@ -36,6 +40,11 @@ module SpeckleConnector
with(:@speckle_state => new_speckle_state)
end
def with_add_queue_js_command(callback_name, js_command)
new_speckle_state = speckle_state.with_add_queue_js_command(callback_name, js_command)
with(:@speckle_state => new_speckle_state)
end
def with_mapped_entities_queue(mapped_entities)
new_speckle_state = speckle_state.with_mapped_entities_queue(mapped_entities)
with(:@speckle_state => new_speckle_state)
+1 -1
View File
@@ -8,7 +8,7 @@ module SpeckleConnector
class UserState
include Immutable::ImmutableUtils
# @return [ImmutableHash{Symbol => Object}] user specific preferences
# @return [Immutable::Hash{Symbol => Object}] user specific preferences
attr_reader :preferences
def initialize(preferences)
@@ -0,0 +1,19 @@
# frozen_string_literal: true
require_relative 'binding'
require_relative '../../actions/get_accounts'
module SpeckleConnector
module Ui
ACCOUNTS_BINDING_NAME = 'accountsBinding'
# Binding that provided for DUI.
class AccountsBinding < Binding
def commands
@commands ||= {
getAccounts: Commands::ActionCommand.new(@app, self, Actions::GetAccounts)
}.freeze
end
end
end
end
@@ -0,0 +1,36 @@
# frozen_string_literal: true
require_relative 'binding'
require_relative '../../constants/path_constants'
require_relative '../../actions/get_source_app_name'
require_relative '../../actions/get_document_info'
require_relative '../../actions/base_actions/add_model'
require_relative '../../actions/base_actions/get_send_filters'
require_relative '../../actions/base_actions/update_send_filter'
require_relative '../../actions/base_actions/get_model_state'
require_relative '../../actions/base_actions/get_document_state'
require_relative '../../actions/base_actions/add_model_to_document_state'
module SpeckleConnector
module Ui
BASE_BINDING_NAME = 'baseBinding'
# Binding that provided for DUI.
class BaseBinding < Binding
def commands
@commands ||= {
addModel: Commands::ActionCommand.new(@app, self, Actions::AddModel),
# Since we send exact model card with updateModel, I can use directly AddModel action, it will replace
updateModel: Commands::ActionCommand.new(@app, self, Actions::AddModel),
getSourceApplicationName: Commands::ActionCommand.new(@app, self, Actions::GetSourceAppName),
getDocumentInfo: Commands::ActionCommand.new(@app, self, Actions::GetDocumentInfo),
updateSendFilter: Commands::ActionCommand.new(@app, self, Actions::UpdateSendFilter),
getModelState: Commands::ActionCommand.new(@app, self, Actions::GetModelState),
getDocumentState: Commands::ActionCommand.new(@app, self, Actions::GetDocumentState),
addModelToDocumentState: Commands::ActionCommand.new(@app, self, Actions::AddModelToDocumentState)
}.freeze
end
end
end
end
@@ -0,0 +1,25 @@
# frozen_string_literal: true
module SpeckleConnector
module Ui
# The abstract class for binding to send data to a user interface.
class Binding
# @return [String] name of the binding.
attr_reader :name
# @return [App::SpeckleConnectorApp] the reference to the app object
attr_reader :app
# @param app [App::SpeckleConnectorApp] the reference to the app object
# @param name [String] name of the binding.
def initialize(app, name)
@app = app
@name = name
end
def commands
raise NotImplementedError, 'Implement in a subclass'
end
end
end
end
@@ -0,0 +1,21 @@
# frozen_string_literal: true
require_relative 'binding'
require_relative '../../actions/config_actions/get_config'
require_relative '../../actions/config_actions/update_config'
module SpeckleConnector
module Ui
CONFIG_BINDING_NAME = 'configBinding'
# Config binding that provided for DUI.
class ConfigBinding < Binding
def commands
@commands ||= {
getConfig: Commands::ActionCommand.new(@app, self, Actions::GetConfig),
updateConfig: Commands::ActionCommand.new(@app, self, Actions::UpdateConfig)
}.freeze
end
end
end
end
@@ -0,0 +1,19 @@
# frozen_string_literal: true
require_relative 'binding'
require_relative '../../actions/selection_actions/get_selection'
module SpeckleConnector
module Ui
SELECTION_BINDING_NAME = 'selectionBinding'
# Selection binding that provided for DUI.
class SelectionBinding < Binding
def commands
@commands ||= {
getSelection: Commands::ActionCommand.new(@app, self, Actions::GetSelection)
}.freeze
end
end
end
end
@@ -0,0 +1,23 @@
# frozen_string_literal: true
require_relative 'binding'
require_relative '../../actions/send_actions/send'
require_relative '../../actions/base_actions/get_send_filters'
require_relative '../../actions/base_actions/update_send_filter'
module SpeckleConnector
module Ui
SEND_BINDING_NAME = 'sendBinding'
# Send Binding that provided for DUI.
class SendBinding < Binding
def commands
@commands ||= {
send: Commands::ActionCommand.new(@app, self, Actions::Send),
getSendFilters: Commands::ActionCommand.new(@app, self, Actions::GetSendFilters),
updateSendFilter: Commands::ActionCommand.new(@app, self, Actions::UpdateSendFilter)
}.freeze
end
end
end
end
+2 -2
View File
@@ -5,7 +5,7 @@ require 'json'
module SpeckleConnector
module Ui
# Command structure to handle it with dialog.exec_callback
CommandData = Struct.new(:name, :data)
CommandData = Struct.new(:name, :binding_name, :resolve_id, :data)
# Parser class for commands that comes from dialog to ruby engine.
class CommandParser
@@ -24,7 +24,7 @@ module SpeckleConnector
return nil unless name.is_a?(String)
CommandData.new(name.to_sym, command['data'])
CommandData.new(name.to_sym, command['binding_name'], command['request_id'], command['data'])
end
end
end

Some files were not shown because too many files have changed in this diff Show More