00001 from diarc.snapkey import gen_snapkey
00002 from diarc.snapkey import parse_snapkey
00003 from diarc.util import TypedDict
00004 from diarc.view import View
00005 from CharGrid import CharGrid
00006
00007 block_spacing = 5
00008
00009 class BlockItem(object):
00010 def __init__(self, parent, index):
00011 self.parent = parent
00012 self._index = index
00013 self.left_block = None
00014 self.right_block = None
00015
00016
00017 self.emitters = list()
00018 self.collectors = list()
00019
00020
00021 self._leftCol = None
00022 self._centerCol = None
00023 self._rightCol = None
00024 self._topRow = None
00025 self._centerRow = None
00026 self._botRow = None
00027
00028
00029 def release(self):
00030 self.left_block = None
00031 self.right_block = None
00032 for item in self.emitters:
00033 item.release()
00034 for item in self.collectors:
00035 item.release()
00036
00037 @property
00038 def leftCol(self):
00039 if self._leftCol is None: self.layout()
00040 return self._leftCol
00041
00042 @property
00043 def centerCol(self):
00044 if self._centerCol is None: self.layout()
00045 return self._centerCol
00046
00047 @property
00048 def rightCol(self):
00049 if self._rightCol is None: self.layout()
00050 return self._rightCol
00051
00052 @property
00053 def topRow(self):
00054 if self._topRow is None: self.layout()
00055 return self._topRow
00056
00057 @property
00058 def centerRow(self):
00059 if self._centerRow is None: self.layout()
00060 return self._centerRow
00061
00062 @property
00063 def botRow(self):
00064 if self._botRow is None: self.layout()
00065 return self._botRow
00066
00067 def layout(self):
00068 if self.left_block is None:
00069 self.left_block = self.parent.corner_stone
00070 self.parent.corner_stone.right_block = self
00071
00072 if None in [self.left_block.topRow,self.left_block.centerRow,self.left_block.topRow]:
00073 self.left_block.layout()
00074 self._topRow = self.left_block.topRow
00075 self._centerRow = self.left_block.centerRow
00076 self._botRow = self.left_block.botRow
00077
00078 if None in [self.left_block.leftCol,self.left_block.centerCol,self.left_block.rightCol]:
00079 self.left_block.layout()
00080 self._leftCol = self.left_block.rightCol + block_spacing + 1
00081 self._centerCol = self.leftCol + 2 + 2*len(self.collectors)
00082 self._rightCol = self.centerCol + 2 + 2*len(self.emitters)
00083
00084 def draw(self,grid):
00085 """ draw this Block into the grid """
00086
00087 grid[(self.topRow,self.leftCol)] = '+-'
00088 grid[(self.centerRow,self.leftCol)] = '| '
00089 grid[(self.botRow,self.leftCol)] = '+-'
00090
00091
00092 grid[(self.topRow,self.leftCol+1)] = "-"*(self.centerCol-self.leftCol-1)
00093 grid[(self.botRow,self.leftCol+1)] = "-"*(self.centerCol-self.leftCol-1)
00094
00095
00096 grid[(self.topRow,self.centerCol)] = '+-'
00097 grid[(self.centerRow,self.centerCol)] = '| '
00098 grid[(self.botRow,self.centerCol)] = '+-'
00099
00100
00101 grid[(self.topRow,self.centerCol+1)] = "-"*(self.rightCol-self.centerCol-1)
00102 grid[(self.botRow,self.centerCol+1)] = "-"*(self.rightCol-self.centerCol-1)
00103
00104
00105 grid[(self.topRow,self.rightCol)] = '+'
00106 grid[(self.centerRow,self.rightCol)] = '|'
00107 grid[(self.botRow,self.rightCol)] = '+'
00108
00109
00110 class BandItem(object):
00111 def __init__(self, parent, altitude, rank):
00112 self.parent = parent
00113 self._altitude = altitude
00114 self._rank = rank
00115 self.top_band = None
00116 self.bot_band = None
00117 self.left_most_snap = None
00118 self.right_most_snap = None
00119
00120
00121 self._row = None
00122 self._startCol = None
00123 self._endCol = None
00124 self._isUsed = False
00125
00126 def release(self):
00127 self.top_band = None
00128 self.bot_band = None
00129 self.left_most_snap = None
00130 self.right_most_snap = None
00131
00132 @property
00133 def row(self):
00134 if self._row is None: self.layout()
00135 return self._row
00136
00137 @property
00138 def startCol(self):
00139 if self._startCol is None: self.layout()
00140 return self._startCol
00141
00142 @property
00143 def endCol(self):
00144 if self._endCol is None: self.layout()
00145 return self._endCol
00146
00147
00148 def layout(self):
00149 if self.bot_band is None:
00150 if self._altitude > 0:
00151 self.bot_band = self.parent.corner_stone
00152 self.parent.corner_stone.top_band = self
00153 self.parent.corner_stone.layout()
00154 return
00155
00156 if self.top_band is None:
00157 if self._altitude > 0:
00158 self.top_band = self.parent.top_line
00159 self.parent.top_line.bot_band = self
00160 else:
00161 self.top_band = self.parent.corner_stone
00162 self.parent.corner_stone.bot_band = self
00163 else:
00164 if self.top_band.row is None:
00165 self.top_band.layout()
00166 self._row = self.top_band.row + 1
00167
00168 if self.left_most_snap.col is None:
00169 self.left_most_snap.layout()
00170 if self.right_most_snap.col is None:
00171 self.right_most_snap.layout()
00172 self._startCol = self.left_most_snap.col+2
00173 self._endCol = self.right_most_snap.col-2
00174
00175
00176 def draw(self,grid):
00177 grid[(self.row,0)] = str(self._altitude)
00178 grid[(self.row,self.startCol)] = '-'*((self.endCol-self.startCol)+1)
00179
00180
00181 class SnapItem(object):
00182 def __init__(self, parent, snapkey):
00183 self.parent = parent
00184 self._snapkey = snapkey
00185 self.block_index, self.container_name, self.snap_order = parse_snapkey(snapkey)
00186
00187 self.block_item = None
00188 self.left_snap = None
00189 self.right_snap = None
00190 self.posBandItem = None
00191 self.negBandItem = None
00192
00193
00194 self.col = None
00195 self.centerRow = None
00196 self.posBandRow = None
00197 self.negBandRow = None
00198
00199 def release(self):
00200 if self.isSource():
00201 self.block_item.emitters.remove(self)
00202 else:
00203 self.block_item.collectors.remove(self)
00204 self.block_item = None
00205 self.left_snap = None
00206 self.right_snap = None
00207 self.posBandItem = None
00208 self.negBandItem = None
00209
00210 def isSource(self):
00211 return True if self.container_name == "emitter" else False
00212
00213 def isSink(self):
00214 return True if self.container_name == "collector" else False
00215
00216 def layout(self):
00217
00218
00219 if self.isSource():
00220 self.col = self.block_item.centerCol
00221 elif self.isSink():
00222 self.col = self.block_item.leftCol
00223 else:
00224 raise Exception("Snap isnt Source or Sink")
00225
00226
00227
00228
00229
00230 self.col += 2 + 2*self.snap_order
00231
00232
00233 self.centerRow = self.block_item.centerRow
00234
00235
00236
00237
00238
00239 def draw(self,grid):
00240 centerRow = self.centerRow
00241 col = self.col
00242 if self.isSink():
00243 if self.posBandItem:
00244
00245 row = self.posBandItem.row
00246 grid[(centerRow-1,col)] = 'V-'
00247 grid[(row,col-1)] = '.'
00248 for i in range(centerRow-2-row):
00249 grid[(centerRow-2-i,col)] = '|'
00250 if self.negBandItem:
00251
00252 row = self.negBandItem.row
00253 grid[(centerRow+1,col)] = 'A-'
00254 grid[(row,col+1)] = "'"
00255 for i in range(row-(centerRow+2)):
00256 grid[(centerRow+2+i,col)] = '|'
00257 elif self.isSource():
00258 if self.posBandItem:
00259
00260 row = self.posBandItem.row
00261 grid[(centerRow-1,col)] = 'A-'
00262 grid[(row,col+1)] = '.'
00263 for i in range(centerRow-2-row):
00264 grid[(centerRow-2-i,col)] = '|'
00265 if self.negBandItem:
00266
00267 row = self.negBandItem.row
00268 grid[(centerRow+1,col)] = 'V-'
00269 grid[(row,col-1)] = "'"
00270 for i in range(row-(centerRow+2)):
00271 grid[(centerRow+2+i,col)] = '|'
00272 else:
00273 raise Exception("Snap is not source or sink")
00274
00275
00276 class TopLine(object):
00277 def __init__(self):
00278 self.row = 0
00279
00280
00281 self.below = None
00282
00283 def layout(self):
00284 self.row = 0
00285
00286 def draw(self):
00287 pass
00288
00289
00290 class CornerStone(object):
00291 """ What everything tries to be relative to """
00292 def __init__(self):
00293
00294 self.rightBlock = None
00295
00296 self.top_band = None
00297 self.bot_band = None
00298
00299 self.leftCol = None
00300 self.centerCol = None
00301 self.rightCol = None
00302 self.topRow = None
00303 self.centerRow = None
00304 self.botRow = None
00305
00306 @property
00307 def row(self):
00308 """ return a calculated row since the spacing here is non-standard. Basically
00309 we return the empty row below the band of Blocks. This is used for band layout """
00310 if not self.botRow:
00311 self.layout()
00312 return self.botRow+1
00313
00314
00315 def layout(self):
00316
00317 if self.top_band is None:
00318 self.topRow = 0
00319 self.centerRow = 1
00320 self.botRow = 2
00321 else:
00322 if self.top_band.row is None:
00323 self.top_band.layout()
00324 self.topRow = self.top_band.row + 2
00325 self.centerRow = self.topRow+1
00326 self.botRow = self.centerRow+1
00327
00328 self.leftCol = -block_spacing-1
00329 self.centerCol = -block_spacing-1
00330 self.rightCol = -block_spacing-1
00331
00332 def draw(self,grid):
00333
00334 pass
00335
00336
00337
00338
00339 class AsciiView(View):
00340 def __init__(self):
00341 View.__init__(self)
00342
00343
00344 self.top_line = TopLine()
00345 self.corner_stone = CornerStone()
00346
00347
00348 self._block_items = TypedDict(int, BlockItem)
00349 self._band_items = TypedDict(int, BandItem)
00350 self._snap_items = TypedDict(str, SnapItem)
00351
00352 def add_block_item(self, index):
00353 """ Create new a drawable object to correspond to a Block with this index. """
00354 if not index in self._block_items:
00355 print "Adding block item",index
00356 item = BlockItem(self, index)
00357 self._block_items[index] = item
00358 return item
00359
00360 def has_block_item(self, index):
00361 return True if index in self._block_items else False
00362
00363 def set_block_item_settings(self, index, left_index, right_index):
00364 item = self._block_items[index]
00365 item.left_block = self._block_items[left_index] if left_index is not None else None
00366 item.right_block = self._block_items[right_index] if right_index is not None else None
00367
00368 def set_block_item_attributes(self, index, attributes):
00369 """ Not yet implemented """
00370 pass
00371
00372 def remove_block_item(self, index):
00373 print "Removing BlockItem %d"%index
00374 self._block_items[index].release()
00375 self._block_items.pop(index)
00376
00377 def add_band_item(self, altitude, rank):
00378 """ Create a new drawable object to correspond to a Band. """
00379 print "Adding BandItem with altitude %d"%altitude
00380 if altitude in self._band_items:
00381 raise DuplicateItemExistsError("BandItem with altitude %d already exists"%(altitude))
00382 item = BandItem(self, altitude, rank)
00383 self._band_items[altitude] = item
00384 return item
00385
00386 def has_band_item(self, altitude):
00387 return True if altitude in self._band_items else False
00388
00389 def remove_band_item(self, altitude):
00390 """ Remove the drawable object to correspond to a band """
00391 print "Removing BandItem altitude %d"%altitude
00392 self._band_items[altitude].release()
00393 self._band_items.pop(altitude)
00394
00395 def get_band_item(self, altitude):
00396 return self._band_items[altitude]
00397
00398 def set_band_item_settings(self, altitude, rank,
00399 top_band_alt, bot_band_alt,
00400 leftmost_snapkey, rightmost_snapkey):
00401 item = self._band_items[altitude]
00402 item.top_band = self._band_items[top_band_alt] if top_band_alt is not None else None
00403 item.bot_band = self._band_items[bot_band_alt] if bot_band_alt is not None else None
00404 item.left_most_snap = self._snap_items[leftmost_snapkey]
00405 item.right_most_snap = self._snap_items[rightmost_snapkey]
00406
00407 def set_band_item_attributes(self, index, attributes):
00408 """ not yet implemented for this style view """
00409 pass
00410
00411
00412 def add_snap_item(self, snapkey):
00413 print "Adding SnapItem %s"%snapkey
00414 if snapkey in self._snap_items:
00415 raise DuplicateItemExistsError("SnapItem with snapkey %s already exists"%(snapkey))
00416 item = SnapItem(self, snapkey)
00417 item.block_item = self._block_items[item.block_index]
00418 if item.isSource():
00419 self._block_items[item.block_index].emitters.append(item)
00420 else:
00421 self._block_items[item.block_index].collectors.append(item)
00422 self._snap_items[snapkey] = item
00423 return item
00424
00425 def remove_snap_item(self, snapkey):
00426 print "Removing SnapItem %s"%snapkey
00427 self._snap_items[snapkey].release()
00428 self._snap_items.pop(snapkey)
00429
00430 def has_snap_item(self, snapkey):
00431 return True if snapkey in self._snap_items else False
00432
00433
00434 def set_snap_item_settings(self, snapkey, left_order, right_order, pos_band_alt, neg_band_alt):
00435 item = self._snap_items[snapkey]
00436 if left_order is not None:
00437 left_snapkey = gen_snapkey(item.block_index,item.container_name,left_order)
00438 item.left_snap = self._snap_items[left_snapkey]
00439 else:
00440 item.left_snap = None
00441 if right_order is not None:
00442 right_snapkey = gen_snapkey(item.block_index,item.container_name,right_order)
00443 item.right_snap = self._snap_items[right_snapkey]
00444 else:
00445 item.right_snap = None
00446 item.posBandItem = self._band_items[pos_band_alt] if pos_band_alt is not None else None
00447 item.negBandItem = self._band_items[neg_band_alt] if neg_band_alt is not None else None
00448
00449 def set_snap_item_attributes(self, snapkey, attributes):
00450 """ not yet implemented for this style view """
00451 pass
00452
00453 def update_view(self):
00454
00455
00456 cornerStone = CornerStone()
00457
00458 for item in self._band_items.values():
00459 item.layout()
00460
00461 for item in self._block_items.values():
00462 item.layout()
00463
00464 for item in self._snap_items.values():
00465 item.layout()
00466
00467
00468 grid = CharGrid()
00469
00470 for item in self._band_items.values():
00471 item.draw(grid)
00472
00473 for item in self._block_items.values():
00474 item.draw(grid)
00475
00476 for item in self._snap_items.values():
00477 item.draw(grid)
00478
00479 print grid
00480
00481
00482
00483
00484 class DuplicateItemExistsError(Exception):
00485 """ An Item with the specified parameters already exists """
00486 pass