module Msf
  module Ui
    module Gtk2

      ##
      # This class perform some tooltips for TreeView widget
      # This class is a port of Daniel J. Popowich coded in Python to ruby-gtk2 style
      ##
      class TreeViewTooltips < Gtk::Window

        def initialize
          super(Gtk::Window::POPUP)
          self.set_resizable(false)
          self.set_border_width(5)
          self.set_app_paintable(true)

          # create the label
          @label = Gtk::Label.new
          @label.set_wrap(true)
          @label.set_alignment(0.5, 0.5)
          @label.set_use_markup(true)
          @label.show()
          self.add(@label)

          # by default, the tooltip is enabled
          @enabled = true
          # saves the current cell
          @save = nil
          # the timer id for the next tooltip to be shown
          @next = nil
          # flag on whether the tooltip window is shown
          @shown = false
        end

        #
        # Enable the tooltip
        #
        def enable
          @enable = true
        end

        #
        # Disable the tooltip
        #
        def disable
          @enable = false
        end


        #
        # Handler to be connected on to the Gtk::Treeview
        #
        def add_view(view)

          # Enter
          view.signal_connect('motion-notify-event') do |view, event|
            motion_handler(view, event)
          end

          # Leave
          view.signal_connect('leave-notify-event') do |view, event|
            leave_handler(view, event)
          end
        end


        #
        # Given the x,y coordinates of the pointer and the width and
        # height (w,h) demensions of the tooltip window, return the x, y
        # coordinates of the tooltip window.
        #
        # The default location is to center the window on the pointer
        # and 20 pixels below it.
        #
        def location(x, y, w, h)
          return x - w/2, y + 20
        end


        #########
        private #
        #########

        #
        # show the tooltip popup with the text/markup given by
        # tooltip.
        #
        # tooltip: the text/markup for the tooltip.
        # x, y:  the coord. (root window based) of the pointer.
        #
        def show(tooltip, x, y)
          # set label
          @label.set_label(tooltip)

          # resize window
          w, h = self.size_request()

          # Display the window with a 1-pixel black border
          self.style.paint_flat_box(	self.window, 		# window: a Gdk::Window
          Gtk::STATE_NORMAL,	# state_type: a state type (GtkStateType)
          Gtk::SHADOW_OUT, 	# shadow_type: a shadow type (GtkShadowType)
          nil, 			# area: a Gdk::Rectangle to which the output is clipped
          self, 			# widget: a Gtk::Widget
          'tooltip', 		# detail: a String or nil
          0, 			# x:
          0, 			# y:
          w, 			# width:
          h			# height:
          )

          # move the window
          self.move(*location(x,y,w,h))

          # show it
          self.show_all
          @shown = true
        end

        #
        # hide the tooltip
        #
        def hide_me
          queue_next()
          self.hide()
          @shown = false
        end

        #
        # When the pointer leaves the view, hide the tooltip
        #
        def leave_handler(view, event)
          hide_me()
        end

        #
        # As the pointer moves across the view, show a tooltip.
        #
        def motion_handler(view, event)

          path = view.get_path_at_pos(event.x, event.y)

          if (@enabled and path)
            path, col, x, y = path
            tooltip = get_tooltip(view, col, path)
            if tooltip
              tooltip = tooltip.strip
              queue_next( [path, col], tooltip, event.x_root, event.y_root)
              return
            end
          end

          hide_me()
        end

        #
        # queue next request to show a tooltip
        #
        def queue_next(*args)

          # if args is non-empty it means a request was made to show a
          # tooltip.  if empty, no request is being made, but any
          # pending requests should be cancelled anyway.

          cell = nil

          # if called with args, break them out
          if args
            cell, tooltip, x, y = args
          end

          # if it's the same cell as previously shown, just return
          if (@save == cell)
            return
          end

          # if we have something queued up, cancel it
          if @next
            Gtk.timeout_remove(@next)
            @next = nil
          end

          # if there was a request...
          if cell
            # if the tooltip is already shown, show the new one
            # immediately
            if @shown
              show(tooltip, x, y)
              # else queue it up in 1/2 second
            else
              @next = Gtk.timeout_add(500) { show(tooltip, x, y) }
            end
          end

          # save this cell
          @save = cell
        end
      end

    end
  end
end
