Beispiel #1
0
def edit_layout(request, layout_id):
    """ Respond to the "/edit_layout/NNN/" URL.

        We let the user edit the given tableau layout.
    """
    if not request.user.is_authenticated:
        return HttpResponseRedirect(reverse(settings.ADMIN_HOME_VIEW))

    try:
        layout = TableauLayout.objects.get(id=layout_id)
    except TableauLayout.DoesNotExist:
        return HttpResponseRedirect(
                    reverse("tableau_editor.views.main"))

    tableau = layout.tableau

    # Load the list of TableauLayoutViewPosition records for this layout into
    # memory, adding new records if they don't already exist.

    positions = []

    anchorX = 10
    anchorY = 10

    views = TableauView.objects.filter(tableau=tableau)
    for view in views.order_by("-ordinal_rank"):
        try:
            position = TableauLayoutViewPosition.objects.get(
                                                tableauLayout=layout,
                                                tableauView=view)
        except TableauLayoutViewPosition.DoesNotExist:
            # Create a new view position record for this view.  Note that we
            # have to set the view's rectangle up to have the aspect ratio of
            # the original view bounds, or else the view will be distorted when
            # it is displayed.

            proj = GlobalMercator()

            min_lat  = float(view.min_lat)
            min_long = float(view.min_long)
            max_lat  = float(view.max_lat)
            max_long = float(view.max_long)

            min_x,min_y = proj.LatLonToMeters(min_lat, min_long)
            max_x,max_y = proj.LatLonToMeters(max_lat, max_long)

            viewWidth  = max_x - min_x
            viewHeight = max_y - min_y

            if viewWidth == 0: viewWidth = 1.0
            if viewHeight == 0: viewHeight = 1.0

            aspectRatio = viewWidth / viewHeight

            boxWidth  = 40
            boxHeight = boxWidth / aspectRatio

            position = TableauLayoutViewPosition()
            position.tableauLayout = layout
            position.tableauView   = view
            position.min_x         = anchorX
            position.min_y         = anchorY
            position.max_x         = anchorX + boxWidth
            position.max_y         = anchorY + boxHeight
            position.save()

            anchorX = anchorX + 20
            if anchorX > layout.width - 10:
                anchorX = 10

            anchorY = anchorY + 20
            if anchorY > layout.height - 10:
                anchorY = 10

        positions.append(position)

    # See what the user wants to do.

    if request.method == "POST":

        if request.POST.get("update_size") != None:
            # The user clicked on the "Update" button to change the layout size
            # -> update the size of the layout.
            new_width = request.POST.get("width")
            if new_width != None:
                try:
                    layout.width = int(new_width)
                except ValueError:
                    pass

            new_height = request.POST.get("height")
            if new_height != None:
                try:
                    layout.height = int(new_height)
                except ValueError:
                    pass

            layout.save()

            return HttpResponseRedirect(
                        reverse("tableau_editor.views.edit_layout",
                                args=[layout.id]))

        if request.POST.get("fit_contents") != None:
            # The user clicked on the "Resize Layout to Fit Contents" button.
            # Calculate the new size for the layout.
            new_width  = 10
            new_height = 10

            for position in positions:
                max_x = request.POST.get("view_"+str(position.id)+"_max_x")
                max_y = request.POST.get("view_"+str(position.id)+"_max_y")

                if max_x != None and max_y != None:
                    max_x = int(max_x)
                    max_y = int(max_y)

                    if max_x > new_width:
                        new_width = max_x

                    if max_y > new_height:
                        new_height = max_y

            layout.width  = new_width
            layout.height = new_height
            layout.save()

            return HttpResponseRedirect(
                        reverse("tableau_editor.views.edit_layout",
                                args=[layout.id]))

        if request.POST.get("save") != None:
            # The user clicked on the "Save" button -> save the updated layout.
            for position in positions:
                min_x = request.POST.get("view_"+str(position.id)+"_min_x")
                max_x = request.POST.get("view_"+str(position.id)+"_max_x")
                min_y = request.POST.get("view_"+str(position.id)+"_min_y")
                max_y = request.POST.get("view_"+str(position.id)+"_max_y")

                if (min_x != None and min_y != None and max_x != None
                                                    and max_y != None):
                    position.min_x = int(min_x)
                    position.min_y = int(min_y)
                    position.max_x = int(max_x)
                    position.max_y = int(max_y)
                    position.save()

            return HttpResponseRedirect(
                        reverse("tableau_editor.views.edit_tableau",
                                args=[tableau.id]))

        if request.POST.get("cancel") != None:
            # The user clicked on the "Cancel" button -> return to the main
            # "Edit Tableau" page.
            return HttpResponseRedirect(
                        reverse("tableau_editor.views.edit_tableau",
                                args=[tableau.id]))

    # If we get here, we're displaying the form for the first time.  Do so.

    menu_html = menus.generate(request, "Tableau Editor",
                               "tableau_editor", "edit_layout")

    return render_to_response("tableau_editor/templates/edit_layout.html",
                              {'menu_html' : menu_html,
                               'heading'   : "Edit Layout for Tableau '" +
                                             tableau.name + "'",
                               'width'     : layout.width,
                               'height'    : layout.height,
                               'positions' : positions,
                              },
                              context_instance=RequestContext(request))
Beispiel #2
0
def create_tableau(factory, location):
    """ Create a single tableau for a given location using a given factory.

        This function does the actual work of generating an individual tableau
        based upon the factory definition.  It can be called directly to
        generate a desired tableau, or it can be called indirectly by the
        daemon (using the private 'create_tableau' API call) to generate
        tableaux en masse.

        Upon completion, we return None if the tableau-generation attempt was
        successful.  Otherwise, we return a suitable error message explaining
        why the tableau could not be generated.
    """
    # Get the location's outline.

    try:
        outline = Outline.objects.get(location=location)
    except Outline.DoesNotExist:
        # We can't create a tableau for a location without an outline ->
        # tell the user the bad news.
        return "Location has no outline."

    # Delete the existing tableau with this name, if any.

    Tableau.objects.filter(location=location,
                           name=factory.tableau_name).delete()

    # Create the new Tableau for this location.

    tableau = Tableau()
    tableau.location      = location
    tableau.name          = factory.tableau_name
    tableau.meta_data     = factory.tableau_meta_data
    tableau.bounds_render = factory.tableau_bounds_render
    tableau.save()

    # Create a single view for the tableau, covering the location's entire
    # extent.

    min_long,min_lat,max_long,max_lat = outline.outline.extent

    # Add a margin around the edges so that the location is easier to see.

    width = abs(max_long - min_long)
    height = abs(max_lat - min_lat)

    buffer = 0.02 * (width + height) / 2

    min_long = min_long - buffer
    max_long = max_long + buffer
    min_lat  = min_lat  - buffer
    max_lat  = max_lat  + buffer

    # Ensure the calculated view bounds are allowable.

    if min_lat < MIN_ALLOWED_LATITUDE:
        min_lat = MIN_ALLOWED_LATITUDE
    elif min_lat > MAX_ALLOWED_LATITUDE:
        min_lat = MAX_ALLOWED_LATITUDE

    if max_lat < MIN_ALLOWED_LATITUDE:
        max_lat = MIN_ALLOWED_LATITUDE
    elif max_lat > MAX_ALLOWED_LATITUDE:
        max_lat = MAX_ALLOWED_LATITUDE

    if min_long < MIN_ALLOWED_LONGITUDE:
        min_long = MIN_ALLOWED_LONGITUDE
    elif min_long > MAX_ALLOWED_LONGITUDE:
        min_long = MAX_ALLOWED_LONGITUDE

    if max_long < MIN_ALLOWED_LONGITUDE:
        max_long = MIN_ALLOWED_LONGITUDE
    elif max_long > MAX_ALLOWED_LONGITUDE:
        max_long = MAX_ALLOWED_LONGITUDE

    # Create the view.

    view = TableauView()
    view.tableau       = tableau
    view.ordinal_rank  = 1
    view.name          = location.display_name
    view.min_lat       = "%0.4f" % min_lat
    view.max_lat       = "%0.4f" % max_lat
    view.min_long      = "%0.4f" % min_long
    view.max_long      = "%0.4f" % max_long
    view.meta_data     = factory.view_meta_data
    view.bounds_render = factory.view_bounds_render
    view.save()

    # Add the factory's filter(s) to the tableau's view.

    for factory_filter in factory.tableaufactoryviewfilter_set.all():
        filter = TableauViewFilter()
        filter.tableauView    = view
        filter.type           = factory_filter.filter_type
        filter.value          = factory_filter.filter_value
        filter.meta_data      = factory_filter.filter_meta_data
        filter.draw_bubbles   = factory_filter.filter_draw_bubbles
        filter.polygon_render = factory_filter.filter_polygon_render
        filter.bubble_render  = factory_filter.filter_bubble_render
        filter.save()

    # Calculate the aspect ratio for the tableau's view.

    proj = GlobalMercator()

    min_x,min_y = proj.LatLonToMeters(min_lat, min_long)
    max_x,max_y = proj.LatLonToMeters(max_lat, max_long)

    viewWidth  = max_x - min_x
    viewHeight = max_y - min_y

    if viewWidth == 0: viewWidth = 1.0
    if viewHeight == 0: viewHeight = 1.0

    aspectRatio = viewWidth / viewHeight

    # Create a single layout for the tableau.  The size of the layout is
    # based on the view's aspect ratio.

    layout_width = LAYOUT_MAX_WIDTH
    layout_height = layout_width / aspectRatio

    if layout_height > LAYOUT_MAX_HEIGHT:
        layout_height = LAYOUT_MAX_HEIGHT
        layout_width  = layout_height * aspectRatio

    layout = TableauLayout()
    layout.tableau = tableau
    layout.width   = layout_width
    layout.height  = layout_height
    layout.save()

    # Create a single TableauLayoutViewPosition record, positioning the view
    # within the layout.

    position = TableauLayoutViewPosition()
    position.tableauLayout = layout
    position.tableauView   = view
    position.min_x         = 0
    position.min_y         = 0
    position.max_x         = layout_width
    position.max_y         = layout_height
    position.save()

    # Finally, tell the caller that the tableau was successfully generated.

    return None