-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDComponentReporter.rb
More file actions
executable file
·336 lines (302 loc) · 11.1 KB
/
Copy pathDComponentReporter.rb
File metadata and controls
executable file
·336 lines (302 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
#----------------------------------------------------------------------------#
## Copyright 2015-2015, tobiashochguertel.de
#
# @author Tobias, Hochguertel <tobias.hochguertel@googlemail.com>
# @version: 0.1.0
#
## Copyright 2005-2008, Google, Inc.
# ShoreStation Dock Quote generator
# Modifiled on 4-13-2009 by Jon Devitt jon.devitt@gmail.com
# Original code provided by Scott Lininger at Sketchup
#----------------------------------------------------------------------------#
require 'sketchup.rb'
# Monkeypatching the hash to allow the uniq function of array to work...
class Hash
def hash
to_a.hash
end
alias eql? ==
end
# AttributeReporter class, provide useful reporting for the attributes attached to your
# Components and Groups
class DCompReporter
# Setup for filetypes
def set_up(filename)
@group_list = []
@component_list = []
# Dictionary where the DC attributes are stored.
@dictionary_name = "dynamic_attributes"
# Create some global structures to store our report data in as
# it is built. Note that this is a RAM intensive approach, so extremely
# large reports could run into memory problems.
@report_data = []
# This array will contain an ordered list of the attribute names we've
# encountered as we walk the model.
@report_attribute_list = []
#Array of items with an itemcode attribute value.
@item_list = []
@notelist = []
# Calculate the file type based on the characters after the last dot in the file name.
@filetype = (filename.split('.').last).downcase
@filename = filename
# In an effort to allow for extending the report formats down the
# road, the reporter uses a simple templating system that allows you to
# define strings that start and end the report, the rows, and the cells.
# you can easily add more formats here
if @filetype == "csv"
@doc_start = ""
@doc_end = ""
@row_start = ""
@row_end = "\n"
@cell_start = ""
@cell_mid = ","
@cell_end = ","
@totalrow = ",,,Total Price:"
end
if @filetype == "md"
@doc_start = ""
@doc_end = ""
@row_start = "| "
@row_end = "|\n"
@cell_start = " "
@cell_mid = "|"
@cell_end = " "
@totalrow = ""
end
if @filetype == "html"
@doc_start = "<html><head><meta http-equiv=\"Content-Type\" " +
"content=\"text/html; charset=utf-8\"><title>Component List</title>" +
"<style> table {\n" +
" padding: 0px;\n" +
" margin: 0px;\n" +
" empty-cells: show;\n" +
" border-right: 1px solid silver;\n" +
" border-bottom: 1px solid silver;\n" +
" border-collapse: collapse;\n" +
"}\n" +
"td {\n" +
" padding: 4px;\n" +
" margin: 0px;\n" +
" border-left: 1px solid silver;\n" +
" border-top: 1px solid silver;\n" +
" font-family: sans-serif;\n" +
" font-size: 9pt;\n" +
" vertical-align: top;\n" +
"}\n" +
"</style>\n" +
"</head>\n" +
"<body>\n" +
"<table border=1>"
createtime = Time.new
@doc_end = "</body><div></html>"
@table_end = "</table>"
@row_start = " <tr>\n"
@row_end = " </tr>\n"
@cell_start = " <td>"
@cell_mid = "</td>\n <td>"
@cell_end = "</td>\n"
@totalrow = "<td colspan = 4 align = \"right\">" + "<b>Total Price:</b>  "
end
end
# This method returns a named attribute from the DC dictionary. It looks
# on the instance first... if no attribute is found there, it looks on
# the definition next.
#
# Args:
# entity: reference to the entity to get the value from
# name: string name of the attribute to return the value for
#
# Returns:
# the value of the attribute, or nil if it can't determine that
def get_attribute_value(entity,name)
name = name.downcase
if entity.typename == 'ComponentInstance'
value = entity.get_attribute @dictionary_name, name
if value == nil
value = entity.definition.get_attribute(@dictionary_name, name)
end
return value
elsif entity.typename == 'Group' || entity.typename == "Model" ||
entity.typename == 'ComponentDefinition'
return entity.get_attribute(@dictionary_name, name)
else
return nil
end
end
# This methods loops through all the model entities and process them in case they are
# either Components or Groups. Here more functionality can be added in case we want
# to report about different entities.
#
# Args:
# list: beginning entities list used to communicate to this function
# whether or not we are processing all the model entities or just the current
# selection
#
# Returns:
# None
# Modified to call the create_item_list function to grab only the Item Number and Description attributes
def collect_attributes(list)
n = 0
# Determine the number and types of entities.
while list != [] # While there are still entities in the list array, determine their type and count them.
list.each do |item|
n +=1
type = item.typename
case type
when "Group"
item.entities.each do |entity| # Add all the entities that are in that group into the group_list array.
@group_list.push entity
end
#get the attributes and put them in the report string
@group_list.delete(item)
create_item_list(item, n)
when "ComponentInstance"
# You can call .entities on Component Definition, but not on Component Instance.
# You need to figure out which ComponentDefinition the instance belongs to. (ComponentDefinition=ComponentInstance.definition)
item.definition.entities.each do |entity|
@component_list.push entity # Add all the entities that are in the component to the component_list array.
end
#get the attributes and put them in the report string
create_item_list(item, n)
#get rid of the item we have already examined in the list
@component_list.delete(item)
end
end
# Update the list array so it countains only the entities that were part of sub-groups and sub-arrays. Those sub-entities haven't been counted yet.
list = @group_list + @component_list
# Clear out the group and component lists so they're ready for the next level of sub-groups/components.
@group_list.clear
@component_list.clear
end
end
#Function to get the itemcode and description attributes from the dynamic components. If no value is found for the itemcode, then
#The item is ignored. If item code is found, it is added to the item_list array of hashes.
def create_item_list(entity, number)
item = get_attribute_value(entity,'itemcode')
description = get_attribute_value(entity,'description')
hidden = get_attribute_value(entity,'hidden')
#Bulk items are items to inlcude in the list, but have no model
bulkitems = get_attribute_value(entity,'bulkitems')
#If the item is hidden, we do not include it in the list
if item && hidden != 1
@item_list += [:item => item, :description => description]
end
if bulkitems
temp = bulkitems.split(',')
temp.each do |item|
t = item.strip.split('*').first
q = item.strip.split('*').last
@item_list += [:item => t, :description => ""]*q.to_i
end
end
end
# This method format the @report_data string assembled in create_report_string
# according to the specified file type in @file_type into the @report_string
# Args:
# None
# Returns:
# None
# Modified to list in a 'bom' style format (item, description, quantity, price, and extended price)
def write_report_string
total_price = 0
# Table HEAD
@report_string = @doc_start
@report_string += @row_start
@report_string += @cell_start
@report_string += 'Item'
@report_string += @cell_mid
@report_string += 'Description'
@report_string += @cell_mid
@report_string += 'Quantity'
@report_string += @cell_end
@report_string += @row_end
#Make a list of unique item numbers (consolidated list of items)
append_list = @item_list.uniq
# table BODY
# 1. sort the list
# 2. add the formatting text for HTML or CSV
append_list.sort_by{ |itemlist| itemlist[:item] }.each do |itemlist|
@report_string += @row_start
@report_string += @cell_start
if itemlist[:item]
@report_string += itemlist[:item]
else
""
end
@report_string += @cell_mid
if itemlist[:description]
@report_string += itemlist[:description]
else
@report_string += "---"
end
@report_string += @cell_mid
#Generate the number of times the item number appears in the item list. The is the quantity of items.
quantity = @item_list.select{|w| w == itemlist}.size
@report_string += quantity.to_s
@report_string += @cell_end
@report_string += @row_end
end
empty_cell = @cell_start + @cell_end
@report_string += @doc_end
# Clean up the report data variables to release memory.
@report_attribute_list = nil
@title_array = nil
@report_data = nil
@totals_by_att_name = nil
end
# Sketchup UI Menu Entry.
def generate_attributes_report(filename, entities_list)
# Start an Operation.
Sketchup.active_model.start_operation 'Generate Report', true
model = Sketchup.active_model
view = model.active_view
@filetype = ".html"
@filename = (model.path.sub(/.skp/,""))+".html"
@showprice=0
# Open a save dialog on the last known path by nil.
path = UI.savepanel "Save Report", nil, @filename
if path
@filename=path
set_up(@filename)
else
return
end
#collect all the attributes in the selection or in the model
collect_attributes(entities_list)
# create report data
if write_report_string == -1
return
end
# initialization of all the class variables used
if ( path.split('.').last == nil)
path += @filetype
end
if (path and path.split('.').last == @filetype)
begin
file = File.new(path, "w")
file.print @report_string
rescue
msg = "There was an error saving your report.\n" +
"Please make sure it is not open in any other software " +
"and try again."
ensure
file.close
#Open the report in the default browser.
status = UI.openURL @filename
end
elsif path.nil == false
UI.messagebox "You Have changed the filetype in the save dialog, please try again."
end
# All done, so commit the operation.
Sketchup.active_model.commit_operation
end
end
if( not $dcomp_reporter_loaded )
dcomp_reporter = DCompReporter.new
# Set up some UI hooks.
plugins_menu = UI.menu "Plugins"
plugins_menu.add_item("Generate Summary BOM as HTML") {
dcomp_reporter.generate_attributes_report("report.html", Sketchup.active_model.entities)
}
$dcomp_reporter_loaded = true
end